目录
(1)闭包
(2)装饰器
(3)生成器
(4)协程
(1)闭包
闭包(closure)是很多现代编程语言都有的特点,像C++、Java、JavaScript等都实现或部分实现了闭包功能,很多高级应用都会依靠闭包实现。
一般专业文献上对闭包的定义都比较拗口,比如:“将组成函数的语句和这些语句的执行环境打包在一起时,得到的对象称为闭包。”
其实,简单来说,你可以将闭包看成是一个轻载的类,这个类只有一个函数方法,并且只有为数不多的几个成员变量。 闭包的优点是:实现起来比类稍微轻巧一点(意思就是可以少敲一些代码),并且运行速度比类要快得多(据说约快50%)。下面是一个定义闭包的简单例子:
#Python学习交流群797877325 免费获取系统学习教程
def foo(x, y):
def hellofun():
print('hellofun x is %d, y is %d.' %(x,y))
return hellofun
a = foo(1,2)
b = foo(30,40)
a()
b()
# 运行结果为:
hellofun x is 1, y is 2.
hellofun x is 30, y is 40.
上例中,foo就定义了一个闭包,它将内部定义的函数hellofun返回(但并不运行这个函数), 同时将入参x,y作为以后hellofun要运行时的环境,隐式地与hellofun打包一起返回。 因此,a=foo(1,2) 语句的作用就是:生成一个闭包对象a,这个对象是可作为函数运行的,且其内部含有隐式的成员变量x=1和y=2。 当后面执行 a() 时,会真正运行这个hellofun函数,并且其运行时的环境就是闭包中的:x=1和y=2。
● 查看闭包中变量的内容
续上例:
print(a.__closure__)
print(a.__closure__[0].cell_contents)
print(a.__closure__[1].cell_contents)
# 运行结果为:
(<cell at 0x0000022B7436CFD8: int object at 0x00007FFDB0E37100>,
<cell at 0x0000022B74386288: int object at 0x00007FFDB0E37120>)
1
2
用闭包实现计数器的例子]
def countdown(n):
def next():
nonlocal n # Python3可使用nonlocal关键字,用于声明n为next()函数外部的
变量
r = n
n -= 1
return r
return next
next = countdown(10)
while True:
v = next()
if not v: break
(2)装饰器
装饰器(decorator)是一个函数,其主要用途是包装另一个函数。它可以在不改动原函数的情况下,增强原函数的功能。 相当于给原函数加装了一个增强包。我们来看一个例子:
def square(x):
return x*x
上面是一个计算平方的函数,但是功能非常简单。我们可以通过为其加装装饰器的方法,增强其功能,比如:为这个函数增加打印计算结果的功能。 代码如下:
# 定义装饰器函数
def print_result(func):
def callf(*args, **kwargs):
r = func(*args, **kwargs)
print('The result is %d.' %r)
return r
return callf
# 原函数定义
def square(x):
return x*x
# 用装饰器函数装饰原函数
square = print_result(square)
我们先不管装饰器函数的定义,先看最后一行:
装饰器的原理就是,将原来的函数square作为参数传递给我们新定义的装饰器函数,
再偷偷将square这个名称替换成我们自己定义的装饰器函数print_result中返回的callf函数。这样,当用户执行比如square(2) 语句时, 并不是在执行原来的square函数,而是在运行我们的 callf(2)。
接下来我们再来看装饰器函数中的内容
print_result(func)实际上是定义了一个闭包,和前面的例子中将数据x,y作为闭包环境数据传进来不同,这里将整个square()函数定义作为闭包环境数据传了进来,好在Python中万物皆对象,函数定义本质上也是一个对象,所以将它作为数据传进来也是可以的。
然后在运行callf(2)的时候,将入参"2"通过(*args, **kwargs)参数原封不动地传给了func(*argc, **kwargs)去运行, 而这个func就是闭包对象中的的数据(即原square函数的定义),在运行完func函数之后(其实就是运行了square(2)之后),增加了一句print打印功能, 最后再将func函数返回的结果r再原封不动地返回出去。整个过程就好像给原函数square套了一个壳,故称为装饰器。
运行装饰后的函数:
y = square(2)
print(y)
# 运行结果为:
The result is 4.
4
可以用特殊语法符号@来简写装饰器,以上代码的简写形式为:
# 定义装饰器函数
def print_result(func):
def callf(*args, **kwargs):
r = func(*args, **kwargs)
print('The result is %d.' %r)
return r
return callf
# 用@装饰原函数
@print_result
def square(x):
return x*x
使用多个装饰器
可以对一个原函数使用多个装饰器,其装饰先后顺序为从下到上、从内到外:
@dec1
@dec2
@dec3
def square(x):
pass
# 相当于:
def sq