-
Notifications
You must be signed in to change notification settings - Fork 0
/
decorators.cover
220 lines (170 loc) · 6.07 KB
/
decorators.cover
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
'''
All about decorators.
Identity Function
the output is the same as the input
Higher-order Function
receives a functions as input
add/or returns a function as output
Pure Function
1. always returns the same output for a fiven input
2. no side-effect (only returns a value)
# Note - printing, writing to a file etc are impure functions
Wrapper Function
uses another function ("helper")
typically similar behaviour, but improved
Factory Function
a function that creates and returns a function
Closure:
a place to stash variables from the enclosing scope
only created for a def in a def
1: '''
1: import time, random, math
### Factory functions #########################
1: def pow2(x):
return x ** 2
1: def make_pow(exponent):
103: def power(base):
return base ** exponent
103: return power
1: pow3 = make_pow(3)
1: pow561 = make_pow(561)
1: powers = map(make_pow, range(100))
1: pow8 = make_pow(8)
# print pow8.__closure__[0].cell_contents
# 8
1: def make_logging(func):
1: def logging_wrapper(*args, **kwargs):
print 'calling', func.__name__
print 'with', args, kwargs
result = func(*args, **kwargs)
print 'result was', result
return result
1: return logging_wrapper
1: def make_caching(func):
1: cache = {}
1: def wrapper(*args):
# to deal with kwargs you'd have to convert them in tuple and sort them
# kwargs.items().sorted()
if args in cache:
return cache[args]
result = func(*args)
cache[args] = result
return result
1: return wrapper
1: maxsize = 3
1: def clearing_cache(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
result = func(*args)
if len(cache) >= maxsize:
cache.clear()
cache[args] = result
return result
return wrapper
1: def random_cache(maxsize=10):
2: def decorator(func):
1: cache = {}
1: def wrapper(*args):
15110: if args in cache:
10053: return cache[args]
5057: result = func(*args)
5057: if len(cache) >= maxsize:
4957: del cache[random.choice(list(cache))]
5057: cache[args] = result
5057: return result
1: return wrapper
2: return decorator
# note: original function hidden in the closure
# >>> collatz = make_logging(collatz)
# >>> print collatz.__closure__[0].cell_contents
# <function __main__.collatz>
### Wrapper Functions #########################
1: def logging_sin(x):
print 'calling sin'
print 'with', x
result = math.sin(x)
print 'result was', result
return result
1: def logging_cos(x):
print 'calling cos'
print 'with', x
result = math.cos(x)
print 'result was', result
return result
1: def better_sqrt(x):
'sqrt that works on negative inputs'
if x >= 0:
return math.sqrt(x)
return 1j * math.sqrt(-x)
### (Monkey) Patching #########################
1: import theirs
1: old_sqrt = math.sqrt
1: def patch_better_sqrt(x):
'sqrt that works on negative inputs'
if x >= 0:
return old_sqrt(x)
return 1j * old_sqrt(-x)
1: math.sqrt = patch_better_sqrt
# print theirs.sqrts([4, 81, -25, 16])
### Higher order functions ####################
1: def identity(x):
1: return x
1: registry = {}
1: def register(func):
5: registry[func.__name__] = func
5: return func
1: def add_docstring(func):
4: if func.__doc__ is None:
3: func.__doc__ = 'unknown documentation'
4: return func
### Normal functions #########################
1: def square(x):
return x ** 2
1: square = identity(square)
1: square = register(square)
1: def power(base, exponent):
return base ** exponent
1: power = register(power)
1: power = add_docstring(power)
# decorating collats, note the order
1: @make_logging
1: @register
1: @add_docstring
def collatz(x):
'half or triple plus one'
if x % 2 == 0:
return x // 2
return 3 * x + 1
# equivalent
# collatz = register(collatz)
# collatz = add_docstring(collatz)
# collatz = make_logging(collatz)
1: @make_caching
def conjecture(x):
'recursing collatz arrives at 1 eventually'
if x < 1:
raise ValueError('Must be positive')
if x == 1:
return True
x = collatz(x)
return conjecture(x)
1: conjecture = register(conjecture)
1: conjecture = add_docstring(conjecture)
1: @random_cache
def hardwork(x):
print 'doing hard work'
time.sleep(1)
return x + 1
1: cache = {}
1: def caching_hardwork(x):
if x in cache:
return cache[x]
result = hardwork(x)
cache[x] = result
return result
1: hardwork = register(hardwork)
1: hardwork = add_docstring(hardwork)
# print registry
# help(hardwork)