Small library to work with dependencies in Python
lazy
#
A lazy object is a deferred computation, lambda: 2+2
is a deferred
computation for example, nothing will be called until we execute
Lazy
#
Lazy object representation
Convert a deferred computation into a lazy object using make_lazy
.
Examples:
>>> isinstance(make_lazy(lambda: 1), Lazy)
True
>>> isinstance(lambda: 1, Lazy)
True
>>> x = make_lazy(lambda: 1)
>>> y = lambda: 2
>>> z = x + y
>>> z()
3
lazy(f)
#
Creates a lazy callable from a function
Examples:
>>> from collections import namedtuple
>>> X = lazy(namedtuple('X', 'a b'))
>>> a = lambda: 1
>>> b = lambda: 'foo'
The reference is the same after constructing the object
>>> c = X(a, b=b)
>>> c() is c()
True
>>> c1 = X(a, b=b)
>>> c2 = X(a, b=b)
>>> c1() is c2()
False
You can also use non lazy objects
>>> c = X(a, b=2)
>>> c()
X(a=1, b=2)
Be careful with mutations
>>> c = X(a=make_lazy(lambda: [1]), b=2)
>>> d = c()
>>> d.a[0] = 3
>>> c()
X(a=[3], b=2)
Source code in vacuna/lazy.py
def lazy(f):
"""Creates a lazy callable from a function
Examples:
```python
>>> from collections import namedtuple
>>> X = lazy(namedtuple('X', 'a b'))
>>> a = lambda: 1
>>> b = lambda: 'foo'
```
The reference is the same after constructing the object
```python
>>> c = X(a, b=b)
>>> c() is c()
True
```
```python
>>> c1 = X(a, b=b)
>>> c2 = X(a, b=b)
>>> c1() is c2()
False
```
You can also use non lazy objects
```python
>>> c = X(a, b=2)
>>> c()
X(a=1, b=2)
```
Be careful with mutations
```python
>>> c = X(a=make_lazy(lambda: [1]), b=2)
>>> d = c()
>>> d.a[0] = 3
>>> c()
X(a=[3], b=2)
```
"""
@wraps(f)
def _lazy(*args, **kwargs):
return make_lazy(
lambda: f(
*map_list(args, call_if_lazy),
**map_dict(kwargs, call_if_lazy)
),
name=f.__name__,
)
return _lazy
make_lazy(lazy_obj, name = '')
#
Creates a Lazy object that lets you inspect the properties of the object in a lazy fashion.
Examples:
>>> x = make_lazy(lambda: {'a': [{'b': True}]})
>>> y = x['a'][0]['b']
>>> y()
True
>>> from collections import namedtuple
>>> X = namedtuple('X', 'a b')
>>> x = make_lazy(lambda: X(a=[{'b': True}], b=False))
>>> y = x.a[0]['b']
>>> y()
True
>>> y = x.a[1]['b'] # this line does not break
>>> y()
Traceback (most recent call last):
...
vacuna.lazy.LazyError: error when evaluating `.a[1]`
>>> x = make_lazy(lambda: 2)
>>> y = make_lazy(lambda: 1)
>>> z = x + y
>>> z()
3
>>> x = make_lazy(lambda: [])
>>> x()
[]
>>> x() is x()
True
Source code in vacuna/lazy.py
def make_lazy(lazy_obj, name=''):
"""Creates a Lazy object that lets you inspect the properties of the object
in a lazy fashion.
Examples:
```python
>>> x = make_lazy(lambda: {'a': [{'b': True}]})
>>> y = x['a'][0]['b']
>>> y()
True
```
```python
>>> from collections import namedtuple
>>> X = namedtuple('X', 'a b')
>>> x = make_lazy(lambda: X(a=[{'b': True}], b=False))
>>> y = x.a[0]['b']
>>> y()
True
```
```python
>>> y = x.a[1]['b'] # this line does not break
>>> y()
Traceback (most recent call last):
...
vacuna.lazy.LazyError: error when evaluating `.a[1]`
```
```python
>>> x = make_lazy(lambda: 2)
>>> y = make_lazy(lambda: 1)
>>> z = x + y
>>> z()
3
```
```python
>>> x = make_lazy(lambda: [])
>>> x()
[]
>>> x() is x()
True
```
"""
return _make_lazy(once(lazy_obj), name)
once(f)
#
Execute the given function only once and cache the result
Examples:
Without once
>>> def f(x=[]):
... x.append(1)
... return x
>>> f()
[1]
>>> f()
[1, 1]
With once
>>> @once
... def f(x=[]):
... x.append(1)
... return x
>>> f()
[1]
>>> f()
[1]
Source code in vacuna/lazy.py
def once(f):
"""Execute the given function only once and cache the result
Examples:
Without `once`
```python
>>> def f(x=[]):
... x.append(1)
... return x
>>> f()
[1]
>>> f()
[1, 1]
```
With `once`
```python
>>> @once
... def f(x=[]):
... x.append(1)
... return x
>>> f()
[1]
>>> f()
[1]
```
"""
x = None
executed = False
def _once():
nonlocal x, executed
if not executed:
x = f()
executed = True
return x
return _once