Python函数进阶:闭包、装饰器、生成器、协程

本文详细介绍了Python编程中的四个核心概念:闭包、装饰器、生成器和协程。闭包提供了一种轻量级的类替代方案,用于封装函数和相关环境数据。装饰器允许在不修改原函数代码的情况下增强其功能,通过创建闭包实现函数包装。生成器使用`yield`关键字,允许函数暂停和恢复执行,有效处理大量数据。协程则进一步扩展了生成器,能够接收外部数据并在挂起状态下进行处理,实现并发编程。文章通过实例解析了这些概念,帮助读者深入理解Python的高级特性。
摘要由CSDN通过智能技术生成

目录

(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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值