目录 | 上一节 (7.2 匿名函数) | [下一节 (7.4 装璜器)]()
7.3 返回函数
本节介绍应用函数创立其它函数的思维。
简介
思考以下函数:
def add(x, y): def do_add(): print('Adding', x, y) return x + y return do_add
这是返回其它函数的函数。
>>> a = add(3,4) >>> a <function do_add at 0x6a670> >>> a() Adding 3 4 7
局部变量
请察看外部函数是如何援用内部函数定义的变量的。
def add(x, y): def do_add(): # `x` and `y` are defined above `add(x, y)` print('Adding', x, y) return x + y return do_add
进一步察看会发现,在 add()
函数完结后,这些变量依然放弃存活。
>>> a = add(3,4) >>> a <function do_add at 0x6a670> >>> a() Adding 3 4 # Where are these values coming from? 7
闭包
当外部函数作为后果返回时,该外部函数称为闭包(closure)。
def add(x, y): # `do_add` is a closure def do_add(): print('Adding', x, y) return x + y return do_add
根本个性:闭包保留该函数当前失常运行所需的所有变量的值。能够将闭包视作一个函数,该函数领有一个额定的环境来保留它所依赖的变量的值。
应用闭包
尽管闭包是 Python 的根本个性,然而它们的用法通常很奥妙。常见利用:
- 在回调函数中应用。
- 提早计算。
- 装璜器函数(稍后介绍)。
提早计算
思考这样的函数:
def after(seconds, func): import time time.sleep(seconds) func()
应用示例:
def greeting(): print('Hello Guido') after(30, greeting)
after
(提早30 秒后)执行给定的函数……
闭包附带了其它信息。
def add(x, y): def do_add(): print(f'Adding {x} + {y} -> {x+y}') return do_add def after(seconds, func): import time time.sleep(seconds) func() after(30, add(2, 3)) # `do_add` has the references x -> 2 and y -> 3
代码反复
闭包也能够用作一种防止代码大量反复的技术。
练习
练习 7.7:应用闭包防止反复
闭包的一个更弱小的个性是用于生成反复的代码。让咱们回顾 练习 5.7 代码,该代码中定义了带有类型查看的属性:
class Stock: def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price ... @property def shares(self): return self._shares @shares.setter def shares(self, value): if not isinstance(value, int): raise TypeError('Expected int') self._shares = value ...
与其一遍又一遍地输出代码,不如应用闭包主动创立代码。
请创立 typedproperty.py
文件,并把下述代码放到文件中:
# 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 {expected_type}') 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:简化函数调用
在下面示例中,用户可能会发现调用诸如 typedproperty('shares', int)
这样的办法略微有点简短 ——尤其是多次重复调用的时候。请将以下定义增加到 typedproperty.py
文件中。
String = lambda name: typedproperty(name, str) Integer = lambda name: typedproperty(name, int) Float = lambda name: typedproperty(name, float)
当初,请从新编写 Stock
类以应用以下函数:
class Stock: name = String('name') shares = Integer('shares') price = Float('price') def __init__(self, name, shares, price): self.name = name self.shares = shares self.price = price
啊,好一点了。这里的要点是:闭包和 lambda
罕用于简化代码,并打消令人讨厌的代码反复。这通常很不错。
练习 7.9:付诸实践
请从新编写 stock.py
文件中的 Stock
类,以便应用下面展现的类型化个性(typed properties)。
目录 | 上一节 (7.2 匿名函数) | [下一节 (7.4 装璜器)]()
注:残缺翻译见 https://github.com/codists/practical-python-zh