-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlazy.py
124 lines (86 loc) · 2.62 KB
/
lazy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""
Lazy integer arithmetic.
"""
from __future__ import print_function, division
from future.utils import with_metaclass
import abc
class LazyMeta(abc.ABCMeta):
"""Metaclass to simplify creation of lazy methods."""
def __new__(mcs, cls_name, bases, _dict):
for operator in _dict.get('_operators', ()):
_dict[operator] = LazyMethod(operator)
_dict.pop('_operators', None)
return super(LazyMeta, mcs).__new__(mcs, cls_name, bases, _dict)
def lazify(cls, value):
"""Helper function to wrap literal values.
>>> (LazyInteger.lazify(2) + LazyInteger.lazify(3))()
5
>>> LazyInteger.lazify(-100)() == LazyInteger(lambda: -100)()
True
>>> isinstance(LazyString.lazify('hello'), LazyString)
True
"""
return cls(lambda: value)
class LazyMethod(object):
"""Descriptor to easily implement arithmetic operators."""
def __init__(self, method_name=None):
self.method_name = method_name
def __get__(self, instance, cls):
def inner(*others):
def lazy_result():
args = [other.lazy_val() for other in others]
method = getattr(instance.lazy_val(), self.method_name)
return method(*args)
return cls(lazy_result)
return inner
class LazyBase(with_metaclass(LazyMeta, object)):
"""Inherit from this."""
def __init__(self, lazy_val=None):
self.lazy_val = lazy_val or (lambda: self._type())
def __call__(self):
"""Evaluation."""
return self.lazy_val()
@property
def value(self):
"""Evaluates and returns value.
>>> LazyInteger.lazify(-9).value
-9
"""
return self.__call__()
@abc.abstractmethod
def _type(self):
"""Prevent this class from being instantiated."""
class LazyInteger(LazyBase):
"""Lazy integers.
>>> LazyInteger().value
0
>>> a = LazyInteger.lazify(2)
>>> b = LazyInteger.lazify(-3)
>>> (a + b).value
-1
>>> abs(b).value
3
>>> (b * a).value
-6
"""
_type = int
_operators = (
'__add__',
'__sub__',
'__mul__',
'__div__',
'__abs__', # works for unary operators too!
)
class LazyString(LazyBase):
"""Lazy strings.
>>> LazyString()()
''
>>> s1 = LazyString.lazify('hello ')
>>> s2 = LazyString.lazify('world')
>>> (s1 + s2).value
'hello world'
"""
_type = str
_operators = (
'__add__',
)