首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

翻译:《实用的Python编程》07_03_Returning_functions

7.3 返回函数

本节介绍使用函数创建其它函数的思想。

简介

考虑以下函数:

defadd(x,y):

 defdo_add():

     print('Adding',x,y)

     returnx+y

 returndo_add

这是返回其它函数的函数。

>>>a=add(3,4)

>>>a

>>>a()

Adding34

7

局部变量

请观察内部函数是如何引用外部函数定义的变量的。

defadd(x,y):

 defdo_add():

     # `x` and `y` are defined above `add(x, y)`

     print('Adding',x,y)

     returnx+y

 returndo_add

进一步观察会发现,在函数结束后,这些变量仍然保持存活。

>>>a=add(3,4)

>>>a

>>>a()

Adding34     # Where are these values coming from?

7

闭包

当内部函数作为结果返回时,该内部函数称为闭包(closure)。

defadd(x,y):

 # `do_add` is a closure

 defdo_add():

     print('Adding',x,y)

     returnx+y

 returndo_add

基本特性:闭包保留该函数以后正常运行所需的所有变量的值。可以将闭包视作一个函数,该函数拥有一个额外的环境来保存它所依赖的变量的值。

使用闭包

虽然闭包是 Python 的基本特性,但是它们的用法通常很微妙。常见应用:

在回调函数中使用。

延迟计算。

装饰器函数(稍后介绍)。

延迟计算

考虑这样的函数:

defafter(seconds,func):

 importtime

 time.sleep(seconds)

 func()

使用示例:

defgreeting():

 print('Hello Guido')

after(30,greeting)

(延迟30 秒后)执行给定的函数......

闭包附带了其它信息。

defadd(x,y):

 defdo_add():

     print(f'Adding + -> ')

 returndo_add

defafter(seconds,func):

 importtime

 time.sleep(seconds)

 func()

after(30,add(2,3))

# `do_add` has the references x -> 2 and y -> 3

代码重复

闭包也可以用作一种避免代码大量重复的技术。

练习

练习 7.7:使用闭包避免重复

闭包的一个更强大的特性是用于生成重复的代码。让我们回顾练习 5.7代码,该代码中定义了带有类型检查的属性:

与其一遍又一遍地输入代码,不如使用闭包自动创建代码。

请创建文件,并把下述代码放到文件中:

# typedproperty.py

def typedproperty(name, expected_type):

private_name = '_' + name

@property

def prop(self):

return getattr(self, private_name)

@prop.setter

def prop(self, value):

if not isinstance(value, expected_type):

raise TypeError(f'Expected ')

setattr(self, private_name, value)

return prop

现在,通过定义下面这样的类来尝试一下:

from typedproperty import typedproperty

class Stock:

name = typedproperty('name', str)

shares = typedproperty('shares', int)

price = typedproperty('price', float)

def __init__(self, name, shares, price):

self.name = name

self.shares = shares

self.price = price

请尝试创建一个实例,并验证类型检查是否有效:

>>> s = Stock('IBM', 50, 91.1)

>>> s.name

'IBM'

>>> s.shares = '100'

... should get a TypeError ...

>>>

练习 7.8:简化函数调用

在上面示例中,用户可能会发现调用诸如这样的方法稍微有点冗长 ——尤其是多次重复调用的时候。请将以下定义添加到文件中。

String=lambdaname:typedproperty(name,str)

Integer=lambdaname:typedproperty(name,int)

Float=lambdaname:typedproperty(name,float)

现在,请重新编写   类以使用以下函数:

classStock:

 name=String('name')

 shares=Integer('shares')

 price=Float('price')

 def__init__(self,name,shares,price):

     self.name=name

     self.shares=shares

     self.price=price

啊,好一点了。这里的要点是:闭包和常用于简化代码,并消除令人讨厌的代码重复。这通常很不错。

练习 7.9:付诸实践

请重新编写  文件中的类,以便使用上面展示的类型化特性(typed properties)。

注:完整翻译见https://github.com/codists/practical-python-zh

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210322A01B1W00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券