# lazy_stream Module¶

Stream class definition module

Summary of module contents:

Name Description
StreamMeta Stream metaclass. This class overloads all operators to the Stream class, but cmp/rcmp (deprecated), ternary pow (could be called with Stream.map) as well as divmod (same as pow, but this will result in a Stream of tuples).
Stream Stream class. Stream instances are iterables that can be seem as generators with elementwise operators.
avoid_stream Decorator to a class whose instances should avoid casting to a Stream when used with operators applied to them.
tostream Decorator to convert the function output into a Stream. Useful for generator functions.
ControlStream A Stream that yields a control value that can be changed at any time. You just need to set the attribute “value” for doing so, and the next value the Stream will yield is the given value.
MemoryLeakWarning A warning to be used when a memory leak is detected.
StreamTeeHub A Stream that returns a different iterator each time it is used.
thub Tee or “T” hub auto-copier to help working with Stream instances as well as with numbers.
Streamix Stream mixer of iterables.
class StreamMeta[source]

Stream metaclass. This class overloads all operators to the Stream class, but cmp/rcmp (deprecated), ternary pow (could be called with Stream.map) as well as divmod (same as pow, but this will result in a Stream of tuples).

__binary__(op)[source]
__rbinary__(op)[source]
__unary__(op)[source]
class Stream(*dargs)[source]

Bases: collections.abc.Iterable

Stream class. Stream instances are iterables that can be seem as generators with elementwise operators.

Examples:

If you want something like:

>>> import itertools
>>> x = itertools.count()
>>> y = itertools.repeat(3)
>>> z = 2*x + y
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for *: 'int' and ...


That won’t work with standard itertools. That’s an error, and not only __mul__ but also __add__ isn’t supported by their types. On the other hand, you can use this Stream class:

>>> x = Stream(itertools.count()) # Iterable
>>> y = Stream(3) # Non-iterable repeats endlessly
>>> z = 2*x + y
>>> z
<audiolazy.lazy_stream.Stream object at 0x...>
>>> z.take(12)
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25]


>>> from audiolazy import lazy_itertools as itertools
>>> x = itertools.count()
>>> y = itertools.repeat(3)
>>> z = 2*x + y
>>> w = itertools.takewhile(lambda pair: pair[0] < 10, enumerate(z))
>>> list(el for idx, el in w)
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21]


All operations over Stream objects are lazy and not thread-safe.

thub
“Tee” hub to help using the Streams like numbers in equations and filters.
tee
Just like itertools.tee, but returns a tuple of Stream instances.
Stream.tee
Keeps the Stream usable and returns a copy to be used safely.
Stream.copy
Same to Stream.tee.

In that example, after declaring z as function of x and y, you should not use x and y anymore. Use the thub() or the tee() functions, or perhaps the x.tee() or x.copy() Stream methods instead, if you need to use x again otherwhere.

__abs__()[source]
__add__(other)
__and__(other)
__bool__()[source]

Boolean value of a stream, called by the bool() built-in and by “if” tests. As boolean operators “and”, “or” and “not” couldn’t be overloaded, any trial to cast an instance of this class to a boolean should be seen as a mistake.

__call__(*args, **kwargs)[source]

Returns the results from calling elementwise (where each element is assumed to be callable), with the same arguments.

__eq__(other)
__floordiv__(other)
__ge__(other)
__getattr__(name)[source]

Returns a Stream of attributes or methods, got in an elementwise fashion.

__gt__(other)
__ignored_classes__ = (<class 'audiolazy.lazy_filters.LinearFilter'>, <class 'audiolazy.lazy_filters.ZFilter'>, <class 'audiolazy.lazy_filters.CascadeFilter'>, <class 'audiolazy.lazy_filters.ParallelFilter'>)
__init__(*dargs)[source]

Constructor for a Stream.

Parameters: *dargs – The parameters should be iterables that will be chained together. If they’re not iterables, the stream will be an endless repeat of the given elements. If any parameter is a generator and its contents is used elsewhere, you should use the “tee” (Stream method or itertools function) before.

All operations that works on the elements will work with this iterator in a element-wise fashion (like Numpy 1D arrays). When the stream sizes differ, the resulting stream have the size of the shortest operand.

Examples:

A finite sequence:

>>> x = Stream([1,2,3]) + Stream([8,5]) # Finite constructor
>>> x
<audiolazy.lazy_stream.Stream object at 0x...>
>>> tuple(x)
(9, 7)


But be careful:

>>> x = Stream(1,2,3) + Stream(8,5) # Periodic constructor
>>> x
<audiolazy.lazy_stream.Stream object at 0x...>
>>> x.take(15) # Don't try "tuple" or "list": this Stream is endless!
[9, 7, 11, 6, 10, 8, 9, 7, 11, 6, 10, 8, 9, 7, 11]

__invert__()
__iter__()[source]

Returns the Stream contents iterator.

__le__(other)
__lshift__(other)
__lt__(other)
__matmul__(other)
__mod__(other)
__mul__(other)
__ne__(other)
__neg__()
__nonzero__()

Boolean value of a stream, called by the bool() built-in and by “if” tests. As boolean operators “and”, “or” and “not” couldn’t be overloaded, any trial to cast an instance of this class to a boolean should be seen as a mistake.

__or__(other)
__pos__()
__pow__(other)
__radd__(other)
__rand__(other)
__rfloordiv__(other)
__rlshift__(other)
__rmatmul__(other)
__rmod__(other)
__rmul__(other)
__ror__(other)
__rpow__(other)
__rrshift__(other)
__rshift__(other)
__rsub__(other)
__rtruediv__(other)
__rxor__(other)
__sub__(other)
__truediv__(other)
__xor__(other)
append(*other)[source]

Append self with other stream(s). Chaining this way has the behaviour:

self = Stream(self, *others)
blocks(*args, **kwargs)[source]

Interface to apply audiolazy.blocks directly in a stream, returning another stream. Use keyword args.

copy()[source]

Returns a “T” (tee) copy of the given stream, allowing the calling stream to continue being used.

filter(func)[source]

A lazy way to skip elements in the stream that gives False for the given function.

limit(n)[source]

Enforces the Stream to finish after n items.

map(func)[source]

A lazy way to apply the given function to each element in the stream. Useful for type casting, like:

>>> from audiolazy import count
>>> count().take(5)
[0, 1, 2, 3, 4]
>>> my_stream = count().map(float)
>>> my_stream.take(5) # A float counter
[0.0, 1.0, 2.0, 3.0, 4.0]

peek(n=None, constructor=<class 'list'>)[source]

Sees/peeks the next few items in the Stream, without removing them.

Besides that this functions keeps the Stream items, it’s the same to the Stream.take() method.

Stream.take
Returns the n first elements from the Stream, removing them.

Note

When applied in a StreamTeeHub, this method doesn’t consume a copy. Data evaluation is done only once, i.e., after peeking the data is simply stored to be yielded again when asked for.

classmethod register_ignored_class(ignore)[source]
skip(n)[source]

Throws away the first n values from the Stream.

Note

Performs the evaluation lazily, i.e., the values are thrown away only after requesting the next value.

take(n=None, constructor=<class 'list'>)[source]

Returns a container with the n first elements from the Stream, or less if there aren’t enough. Use this without args if you need only one element outside a list.

Parameters: n – Number of elements to be taken. Defaults to None. Rounded when it’s a float, and this can be inf for taking all. constructor – Container constructor function that can receie a generator as input. Defaults to list. The first n elements of the Stream sequence, created by the given constructor unless n == None, which means returns the next element from the sequence outside any container. If n is None, this can raise StopIteration due to lack of data in the Stream. When n is a number, there’s no such exception.
Examples:
>>> Stream(5).take(3) # Three elements
[5, 5, 5]
>>> Stream(1.2, 2, 3).take() # One element, outside a container
1.2
>>> Stream(1.2, 2, 3).take(1) # With n = 1 argument, it'll be in a list
[1.2]
>>> Stream(1.2, 2, 3).take(1, constructor=tuple) # Why not a tuple?
(1.2,)
>>> Stream([1, 2]).take(3) # More than the Stream size, n is integer
[1, 2]
>>> Stream([]).take() # More than the Stream size, n is None
Traceback (most recent call last):
...
StopIteration


Taking rounded float quantities and “up to infinity” elements (don’t try using inf with endless Stream instances):

>>> Stream([4, 3, 2, 3, 2]).take(3.4)
[4, 3, 2]
>>> Stream([4, 3, 2, 3, 2]).take(3.6)
[4, 3, 2, 3]
>>> Stream([4, 3, 2, 3, 2]).take(inf)
[4, 3, 2, 3, 2]


Stream.peek
Returns the n first elements from the Stream, without removing them.

Note

You should avoid using take() as if this would be an iterator. Streams are iterables that can be easily part of a “for” loop, and their iterators (the ones automatically used in for loops) are slightly faster. Use iter() builtin if you need that, instead, or perhaps the blocks method.

avoid_stream(cls)[source]

Decorator to a class whose instances should avoid casting to a Stream when used with operators applied to them.

tostream(func, module_name=None)[source]

Decorator to convert the function output into a Stream. Useful for generator functions.

Note

Always use the module_name input when “decorating” a function that was defined in other module.

class ControlStream(value)[source]

A Stream that yields a control value that can be changed at any time. You just need to set the attribute “value” for doing so, and the next value the Stream will yield is the given value.

Examples:
>>> cs = ControlStream(7)
>>> data = Stream(1, 3) # [1, 3, 1, 3, 1, 3, ...] endless iterable
>>> res = data + cs
>>> res.take(5)
[8, 10, 8, 10, 8]
>>> cs.value = 9
>>> res.take(5)
[12, 10, 12, 10, 12]

__add__(other)
__and__(other)
__eq__(other)
__floordiv__(other)
__ge__(other)
__gt__(other)
__init__(value)[source]
__invert__()
__le__(other)
__lshift__(other)
__lt__(other)
__matmul__(other)
__mod__(other)
__mul__(other)
__ne__(other)
__neg__()
__or__(other)
__pos__()
__pow__(other)
__radd__(other)
__rand__(other)
__rfloordiv__(other)
__rlshift__(other)
__rmatmul__(other)
__rmod__(other)
__rmul__(other)
__ror__(other)
__rpow__(other)
__rrshift__(other)
__rshift__(other)
__rsub__(other)
__rtruediv__(other)
__rxor__(other)
__sub__(other)
__truediv__(other)
__xor__(other)
exception MemoryLeakWarning[source]

Bases: Warning

A warning to be used when a memory leak is detected.

class StreamTeeHub(data, n)[source]

A Stream that returns a different iterator each time it is used.

thub
Auto-copy “tee hub” and helpful constructor alternative for this class.
__add__(other)
__and__(other)
__del__()[source]
__eq__(other)
__floordiv__(other)
__ge__(other)
__gt__(other)
__init__(data, n)[source]
__invert__()
__iter__()[source]
__le__(other)
__lshift__(other)
__lt__(other)
__matmul__(other)
__mod__(other)
__mul__(other)
__ne__(other)
__neg__()
__or__(other)
__pos__()
__pow__(other)
__radd__(other)
__rand__(other)
__rfloordiv__(other)
__rlshift__(other)
__rmatmul__(other)
__rmod__(other)
__rmul__(other)
__ror__(other)
__rpow__(other)
__rrshift__(other)
__rshift__(other)
__rsub__(other)
__rtruediv__(other)
__rxor__(other)
__sub__(other)
__truediv__(other)
__xor__(other)
append(*other)

Append self with other stream(s). Chaining this way has the behaviour:

self = Stream(self, *others)
copy()[source]

Returns a new “T” (tee) copy of this StreamTeeHub without consuming any of the copies done with the constructor.

filter(func)

A lazy way to skip elements in the stream that gives False for the given function.

limit(n)

Enforces the Stream to finish after n items.

map(func)

A lazy way to apply the given function to each element in the stream. Useful for type casting, like:

>>> from audiolazy import count
>>> count().take(5)
[0, 1, 2, 3, 4]
>>> my_stream = count().map(float)
>>> my_stream.take(5) # A float counter
[0.0, 1.0, 2.0, 3.0, 4.0]

skip(n)

Throws away the first n values from the Stream.

Note

Performs the evaluation lazily, i.e., the values are thrown away only after requesting the next value.

take(*args, **kwargs)[source]

Fake function just to avoid using inherited Stream.take implicitly.

Warning

You shouldn’t need to call this method directly. If you need a Stream instance to work progressively changing it, try:

>>> data = thub([1, 2, 3], 2) # A StreamTeeHub instance
>>> first_copy = Stream(data)
>>> first_copy.take(2)
[1, 2]
>>> list(data) # Gets the second copy
[1, 2, 3]
>>> first_copy.take()
3


If you just want to see the first few values, try self.peek(*args, **kwargs) instead.

>>> data = thub((9, -1, 0, 4), 2) # StreamTeeHub instance
>>> data.peek()
9
>>> data.peek(3)
[9, -1, 0]
>>> list(data) # First copy
[9, -1, 0, 4]
>>> data.peek(1)
[9]
>>> second_copy = Stream(data)
>>> second_copy.peek(2)
[9, -1]
>>> data.peek() # There's no third copy
Traceback (most recent call last):
...
IndexError: StreamTeeHub has no more copies left to use.


If you want to consume from every StreamTeeHub copy, you probably should change your code before calling the thub(), but you still might use:

>>> data = thub(Stream(1, 2, 3), 2)
>>> Stream.take(data, n=2)
[1, 2]
>>> Stream(data).take() # First copy
3
>>> Stream(data).take(1) # Second copy
[3]
>>> Stream(data)
Traceback (most recent call last):
...
IndexError: StreamTeeHub has no more copies left to use.

thub(data, n)[source]

Tee or “T” hub auto-copier to help working with Stream instances as well as with numbers.

Parameters: data – Input to be copied. Can be anything. n – Number of copies. A StreamTeeHub instance, if input data is iterable. The data itself, otherwise.
Examples:
>>> def sub_sum(x, y):
...   x = thub(x, 2) # Casts to StreamTeeHub, when needed
...   y = thub(y, 2)
...   return (x - y) / (x + y) # Return type might be number or Stream


With numbers:

>>> sub_sum(1, 1.)
0.0


Combining number with iterable:

>>> sub_sum(3., [1, 2, 3])
<audiolazy.lazy_stream.Stream object at 0x...>
>>> list(sub_sum(3., [1, 2, 3]))
[0.5, 0.2, 0.0]


Both iterables (the Stream input behaves like an endless [6, 1, 6, 1, ...]):

>>> list(sub_sum([4., 3., 2., 1.], [1, 2, 3]))
[0.6, 0.2, -0.2]
>>> list(sub_sum([4., 3., 2., 1.], Stream(6, 1)))
[-0.2, 0.5, -0.5, 0.0]


This function can also be used as a an alternative to the Stream constructor when your function has only one parameter, to avoid casting when that’s not needed:

>>> func = lambda x: 250 * thub(x, 1)
>>> func(1)
250
>>> func([2] * 10)
<audiolazy.lazy_stream.Stream object at 0x...>
>>> func([2] * 10).take(5)
[500, 500, 500, 500, 500]

class Streamix(keep=False, zero=0.0)[source]

Stream mixer of iterables.

Examples:

With integer iterables:

>>> s1 = [-1, 1, 3, 2]
>>> s2 = Stream([4, 4, 4])
>>> s3 = tuple([-3, -5, -7, -5, -7, -1])
>>> smix = Streamix(zero=0) # Default zero is 0.0, changed to keep integers
>>> smix.add(0, s1) # 1st number = delta time (in samples) from last added
>>> smix
<audiolazy.lazy_stream.Streamix object at ...>
>>> list(smix)
[-1, 1, 4, 1, -3, -5, -7, -1]


With time constants:

>>> from audiolazy import sHz, line
>>> s, Hz = sHz(10) # You probably will use 44100 or something alike, not 10
>>> sdata = list(line(2 * s, 1, -1, finish=True))
>>> smix = Streamix()
>>> result = [round(sm, 2) for sm in smix]
>>> len(result)
35
>>> 0.5 * s # Let's see how many samples this is
5.0
>>> result[:7]
[1.0, 0.89, 0.79, 0.68, 0.58, 1.47, 1.26]
>>> result[10:17]
[0.42, 0.21, 0.0, -0.21, -0.42, 0.37, 0.05]
>>> result[-1]
-1.0


ControlStream
Stream (iterable with operators)
sHz
Time in seconds (s) and frequency in hertz (Hz) constants from sample rate in samples/second.
__add__(other)
__and__(other)
__eq__(other)
__floordiv__(other)
__ge__(other)
__gt__(other)
__init__(keep=False, zero=0.0)[source]
__invert__()
__le__(other)
__lshift__(other)
__lt__(other)
__matmul__(other)
__mod__(other)
__mul__(other)
__ne__(other)
__neg__()
__or__(other)
__pos__()
__pow__(other)
__radd__(other)
__rand__(other)
__rfloordiv__(other)
__rlshift__(other)
__rmatmul__(other)
__rmod__(other)
__rmul__(other)
__ror__(other)
__rpow__(other)
__rrshift__(other)
__rshift__(other)
__rsub__(other)
__rtruediv__(other)
__rxor__(other)
__sub__(other)
__truediv__(other)
__xor__(other)
add(delta, data)[source]

Adds (enqueues) an iterable event to the mixer.

Parameters: delta – Time in samples since last added event. This can be zero and can be float. Use “s” object from sHz for time conversion. data – Iterable (e.g. a list, a tuple, a Stream) to be “played” by the mixer at the given time delta.

sHz