forked from fluentpython/example-code
-
Notifications
You must be signed in to change notification settings - Fork 3
Fluent Python读书笔记(六)
18965050 edited this page Jan 9, 2017
·
2 revisions
经典的策略模式实现, 参见: 06-dp-1class-func/classic_strategy.py
由于在Python中, 函数就是对象, 因此可以省去策略接口, 直接使用函数对象.
函数式的策略模式实现, 参见: 06-dp-1class-func/strategy.py
关于装饰器,请记住:
-
装饰器函数能增加或替换被装饰函数
-
装饰器函数在模块加载时, 被装饰函数定义的时候就开始执行了
-
在定义装饰器函数时, 如果忘了添加functools.wraps装饰器, 它会将被装饰函数的元信息拷贝过来
registry = [] # <1> def register(func): # <2> print('running register(%s)' % func) # <3> registry.append(func) # <4> return func # <5> @register # <6> def f1(): print('running f1()') @register def f2(): print('running f2()') def f3(): # <7> print('running f3()') def main(): # <8> print('running main()') print('registry ->', registry) f1() f2() f3() if __name__=='__main__': main() # <9> # 输出 running register(<function f1 at 0x00000000011301E0>) running register(<function f2 at 0x0000000001130268>) running main() registry -> [<function f1 at 0x00000000011301E0>, <function f2 at 0x0000000001130268>] running f1() running f2() running f3()
>>> b = 6
>>> def f2(a):
... print(a)
... print(b)
... b = 9
...
>>> f2(3)
3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f2
UnboundLocalError: local variable 'b' referenced before assignment
上述代码中, 由于在函数内定义了b, 因此函数内b的作用域为local. 又因为b定义在print语句后, 因此抛出了异常. 如果要使用全局的b, 使用global关键字.
要设计一个求平均值的函数, 采用类设计方式, 为:
"""
>>> avg = Averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0
"""
class Averager():
def __init__(self):
self.series = []
def __call__(self, new_value):
self.series.append(new_value)
total = sum(self.series)
return total/len(self.series)
如果采用闭包设计, 为:
"""
>>> avg = make_averager()
>>> avg(10)
10.0
>>> avg(11)
10.5
>>> avg(12)
11.0
>>> avg.__code__.co_varnames
('new_value', 'total')
>>> avg.__code__.co_freevars
('series',)
>>> avg.__closure__ # doctest: +ELLIPSIS
(<cell at 0x...: list object at 0x...>,)
>>> avg.__closure__[0].cell_contents
[10, 11, 12]
"""
DEMO = """
>>> avg.__closure__
(<cell at 0x107a44f78: list object at 0x107a91a48>,)
"""
def make_averager():
series = [] #说明此local变量的作用域并不限制在make_averager函数内
def averager(new_value):
series.append(new_value)
total = sum(series)
return total/len(series)
return averager
先看段代码
def make_averager():
count = 0
total = 0
def averager(new_value):
count += 1
total += new_value
return total / count
return averager
# 运行
avg = make_averager()
avg(10) # UnboundLocalError: local variable 'count' referenced before assignment
上述代码之所以不能运行, 是由于count += 1等价于count=count+1. 此时count就变成averager()函数的local变量了, 由于count没有在averager()函数中定义, 因此报错. 这种情况下就需要使用nonlocal关键字
@d1
@d2
def f():
print('f')
```
等价于
```python
def f():
print('f')
f = d1(d2(f))
```
### 给装饰器添加其他参数
使用一个装饰器工厂返回一个装饰器, 并在此装饰器中装饰被装饰对象
```python
registry = set() # <1>
def register(active=True): # <2>
def decorate(func): # <3>
print('running register(active=%s)->decorate(%s)'
% (active, func))
if active: # <4>
registry.add(func)
else:
registry.discard(func) # <5>
return func # <6>
return decorate # <7>
@register(active=False) # <8> 等价于 register(active=False)(f1)
def f1():
print('running f1()')
@register() # <9>
def f2():
print('running f2()')
def f3():
print('running f3()')
```