7. Function Decorators and Closures
- A decorator is a callable that takes another function as argument (the decorated function). The decorator may perform some processing with the decorated function, and returns it or replaces it with another function or callable object.
1. Variable Scope Rules
b = 6
def f1(a):
print(a) # 3
print(b) # 6
f1(3)
b = 6
def f2(a):
print(a) # 3
print(b) # UnboundLocalError: local variable 'b' referenced before assignment
b = 9
f2(3) # 1. When Python compiles the body of the function, it decides that b is a local
# variable because it's assigned within the function.
# 2. Python does not require you to declare variables, but assumes that a variable
# assigned in the body of a function is local
b = 6
def f3(a):
global b # declare
print(a) # 3
print(b) # 6
b = 9
f3(3)
2. Closures
- Actually, a closure is a function with an extended scope that encompasses nonglobal variables referenced in the body of the function but not defined there. It does not matter whether the function is anonymous or not; what matters is that it can access nonglobal variables that are defined outside of its body.
- A closure is a function that retains the bindings of the free variables that exist when the function is defined, so that they can be used later when the function is invoked and the defining scope is no longer available.
- The only situation in which a function may need to deal with external variables that are nonglobal is when it is nested in another function.
def make_averager():
series = []
def averager(new_value):
series.append(new_value)
total = sum(series)
return total / len(series)
return averager avg = make_averager()
print avg(10) # 10
print avg(12) # 11
print avg(14) # 12
print avg.__code__.co_varnames # ('new_value', 'total')
print avg.__code__.co_freevars # ('series',)
print avg.__closure__ # (<cell at 0x1030d1280: list object at 0x1030a97e8>,)
print avg.__closure__[0].cell_contents # [10, 12, 14]

- free variable: a variable that is not bound in the local scope.
3. The nonlocal Declaration
def make_averager():
count = 0
total = 0
def averager(new_value):
count += 1
total += new_value
return total / count
return averager avg = make_averager()
print avg(10) # UnboundLocalError: local variable 'count' referenced before assignment # 1. We actually assign count in the body of averager, and that makes it a local variable.
# 2. We didn't have this problem before, because we never assigned to the series name,
# we only called series.append and invoked sum and len on it.
# 3. With immutable types, if you try to rebind them, then you are implicitly creating a
# local variable, it's no longer a free variable, therefore it is not saved in the closure.
def make_averager():
count = 0
total = 0
def averager(new_value):
nonlocal count, total # **********
count += 1
total += new_value
return total / count
return averager avg = make_averager()
print(avg(10)) # 10.0 # 1. The nonlocal declaration was introduced in Python 3. It lets you flag a variable as a
# free variable even when it is assigned a new value within the function.
4. Implementing a Simple Decorator
- Typical behavior of a decorator: It replaces the decorated function with a new function that accepts the same arguments and (usually) returns whatever the decorated function was supposed to return, while also doing some extra processing.
def deco(func):
print('running deco()')
print('func -> %s' % str(func))
def inner():
print('running inner()')
return inner @deco # target = deco(target)
def target():
print('running target()') target()
# running deco() # executed immediately when the module is loaded
# func -> <function target at 0x106c460c8>
# running inner()
print(target.__name__) # inner (function is replaced)
import time
FMT = '[{elapsed:0.8f}s] {name}({arg_str}) -> {result}'
def clock(func):
def clocked(*args, **kwargs):
t0 = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - t0 # 用时
name = func.__name__
arg_lst = []
if args:
arg_lst.append(', '.join(repr(arg) for arg in args))
if kwargs:
pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
arg_lst.append(', '.join(pairs))
arg_str = ', '.join(arg_lst)
print(FMT.format(**locals())) # any local variable of clocked
return result
return clocked @clock
def snooze(seconds):
time.sleep(seconds) @clock
def factorial(n):
return 1 if n < 2 else n*factorial(n-1) print('*' * 40, 'Calling snooze(.123)')
snooze(.123)
print('*' * 40, 'Calling factorial(6)')
print('6! =', factorial(6))
# ('****************************************', 'Calling snooze(.123)')
# [0.12694907s] snooze(0.123) -> None
# ('****************************************', 'Calling factorial(6)')
# [0.00000286s] factorial(1) -> 1
# [0.00004411s] factorial(2) -> 2
# [0.00005984s] factorial(3) -> 6
# [0.00007296s] factorial(4) -> 24
# [0.00014281s] factorial(5) -> 120
# [0.00015783s] factorial(6) -> 720
# ('6! =', 720)
5. Decorators in the Standard Library
5.1 functools.wraps
import functools
def deco(func):
@functools.wraps(func) # copy the relevant attributes from func to inner
def inner():
print('running inner()')
return inner @deco
def target():
"""i'm target"""
print('running target()') target() # running inner()
print(target.__name__) # target
print(target.__doc__) # i'm target
5.2 functools.lru_cache
- An optimization technique that works by saving the results of previous invocations of an expensive function, avoiding repeat computations on previously used arguments.
- The cache is limited by discarding the entries that have not been read for a while.
import functools
@functools.lru_cache() # Python 3
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1) print(fibonacci(6))
# [0.00000095s] fibonacci(0) -> 0
# [0.00000215s] fibonacci(1) -> 1
# [0.00036097s] fibonacci(2) -> 1
# [0.00000167s] fibonacci(3) -> 2
# [0.00039101s] fibonacci(4) -> 3
# [0.00000095s] fibonacci(5) -> 5
# [0.00041699s] fibonacci(6) -> 8
# 8 # @functools.lru_cache(maxsize=128, typed=False)
# maxsize: how many call results are stored. (should be a power of 2)
# typed: True -> store results of different argument types separately (1 / 1.0)
# False -> don't store # [notes]: lru_cache uses a dict to store the results, all the arguments
# taken by the decorated function must be hashable.
5.3 functools.singledispatch
- The new functools.singledispatch decorator in Python 3.4 allows each module to contribute to the overall solution, and lets you easily provide a specialized function even for classes that you can’t edit.
- If you decorate a plain function with @singledispatch, it becomes a generic function: a group of functions to perform the same operation in different ways, depending on the type of the first argument.
from functools import singledispatch
from collections import abc
import numbers
import html @singledispatch # mark the base function handles the obj type.
def htmlize(obj):
content = html.escape(repr(obj))
return '<pre>{}</pre>'.format(content) @htmlize.register(str) # @«base_function».register(«type»).
def _(text): # name of the specialized functions is irrelevant
return '<p>{0}</p>'.format(html.escape(text)) @htmlize.register(numbers.Integral)
def _(n):
return '<pre>{0} (0x{0:x})</pre>'.format(n) @htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
inner = '</li>\n<li>'.join(htmlize(item) for item in seq)
return '<ul>\n<li>' + inner + '</li>\n</ul>' print(htmlize(str)) # <pre><class 'str'></pre>
print(htmlize('<hello>')) # <p><hello></p>
print(htmlize(10)) # <pre>10 (0xa)</pre>
print(htmlize(['alpha', {3, 2, 1}]))
# <ul>
# <li><p>alpha</p></li>
# <li><pre>{1, 2, 3}</pre></li>
# </ul> # 1. Register the specialized functions to handle ABCs (abstract classes)
# instead of concrete implementations like int and list. (support more)
# 2. A notable quality of the singledispatch mechanism is that you can
# register specialized functions anywhere in the system, in any module.
6. Stacked Decorators
@d1
@d2
def f():
print('f') # f = d1(d2(f))
7. Parameterized Decorators
- Make a decorator factory that takes those arguments and returns a decorator, which is then applied to the function to be decorated.
def outter(a=1):
def deco(func):
def inner():
if a == 1:
print(1)
else:
print(a)
return inner
return deco @outter()
def target1():
pass @outter(9)
def target2():
pass target1() # 1
target2() # 9
7. Function Decorators and Closures的更多相关文章
- 《流畅的Python》Data Structures--第7章 colsure and decorator
Function Decorators and Closures 装饰器是用于增强函数的行为,理解它,就必须先理解闭包. Python3引入关键字nonlocal,如果要理解闭包,就必须了解它的所有方 ...
- 浅入浅出Typescript Decorators
临时起的兴趣,想写一篇关于ts decorator的文章,就花小半天整理了一下... 这东西,在ES2017里好像也有... 文档的话看这里. 因为临时,就没想写太多文字介绍,带少许文字说明直接开撸 ...
- JavaScript Decorators 的简单理解
Decorators,装饰器的意思, 所谓装饰就是对一个物件进行美化,让它变得更漂亮.最直观的例子就是房屋装修.你买了一套房子,但是毛坯房,你肯定不想住,那就对它装饰一下,床,桌子,电视,冰箱等一通买 ...
- TypeScript学习笔记(九):装饰器(Decorators)
装饰器简介 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式. 需要注意的是:装饰器是一项实验性特性,在未来的版本中可能会发生改变. 若要启用实验性的装饰器特 ...
- 《dive into python3》 笔记摘录
1.list can hold arbitrary objects and can expand dynamically as new items are added. A list is an ...
- JAVASCRIPT的一些知识点梳理
春节闲点,可以安心的梳理一下以前不是很清楚的东东.. 看的是以下几个URL: http://web.jobbole.com/82520/ http://blog.csdn.net/luoweifu/a ...
- [TypeScript] Reflection and Decorator Metadata
TypeScript allows you to emit decorator metadata which enables more powerful features through reflec ...
- python函数与方法装饰器
之前用python简单写了一下斐波那契数列的递归实现(如下),发现运行速度很慢. def fib_direct(n): assert n > 0, 'invalid n' if n < 3 ...
- 是什么让javascript变得如此奇妙
What Makes Javascript Weird...and AWESOME -> First Class Functions -> Event-Driven Evironment ...
随机推荐
- unity3d 触屏多点触控(旋转与缩放)
unity3d 触屏多点触控(旋转与缩放) /*Touch OrbitProgrammed by: Randal J. Phillips (Caliber Mengsk)Original Creati ...
- Flutter 贝塞尔曲线切割
现在人们对于网站的美感要求是越来越高了,所以很多布局需要优美的曲线设计.当然最简单的办法是作一个PNG的透明图片,然后外边放一个Container.但其内容如果本身就不是图片,只是容器,这种放入图片的 ...
- (IStool)删除新版本已废弃但可能会影响新版本运行的文件夹/文件
需求:老版本服务器的某些文件或文件夹在新版本已弃用,新版本覆盖安装时需要将文件夹或文件删除 实现:覆盖安装完成后将对应目录下的文件删除 [InstallDelete] Type: files; Nam ...
- 《剑指offer》树专题 (牛客10.25)
考察的知识点主要在于树的数据结构(BST,AVL).遍历方式(前序,中序,后序,层次).遍历算法(DFS,BFS,回溯)以及遍历时借助的数据结构如队列和栈.由于树本身就是一个递归定义的结构,所以在递归 ...
- nload 安装和使用
nload是一个很小巧的工具,用来监控当前系统的网速 安装 MAC brew install nload Linux 下载地址:https://sourceforge.net/projects/nlo ...
- vue项目中event bus的简单使用
之前做的一个vue后台管理系统中,需要实现这样一个功能:从列表页点击新建或编辑进入新建.编辑页面,新建.编辑完成后需要关闭当前的新建和编辑tab,而tab的关闭则是由项目中的tag组件控制的, 新建和 ...
- Union All 使用注意事项和字段顺序不一致导致的异常
使用注意,先说结果: UNION 操作符用于合并两个或多个 SELECT 语句的结果集,这里需要注意的是: UNION 内部的 SELECT 语句必须拥有相同数量的列: 列也必须拥有相似的数据类型(实 ...
- pandas越来越难学,只能自己找趣味了,你该这么学,No.11
啊,大海啊,全是水 pandas啊,全是坑 没错,今天继续学习难的 其实从这篇开始,每一篇都是难得...... 你必须要努力看了 文末有彩蛋 分层/多级索引 我们先创建一个分层索引,看看效果 这个创建 ...
- 要求设计 LazyMan 类,实现以下功能
LazyMan('Tony'); // Hi I am Tony LazyMan('Tony').sleep(10).eat('lunch'); // Hi I am Tony // 等待了10秒.. ...
- [转帖]IBM 开源 POWER 指令集架构
IBM 开源 POWER 指令集架构 https://www.solidot.org/story?sid=61791 新闻越短 事情越严重 IBM 破釜沉舟 OpenPOWER 联盟国产化披荆斩棘? ...