深入浅出 Python Closures

原文

Nonlocal variable in a nested function

nested function: 一个函数定义在顶一个函数内部
nested function 可以访问 enclosing scope(即包裹着它的更大的空间)中的变量,这些变量相对于它称之为 nonlocal variable。
Nonlocal variables 是只读的,如果想修改它们,必须使用 nonlocal 关键字。

在 Python 2 中对应 global

def print_msg(msg):
# This is the outer enclosing function

    def printer():
# This is the nested function
        print(msg)

    printer()

# We execute the function
# Output: Hello
print_msg("Hello")

We can see that the nested function printer() was able to access the non-local variable msg of the enclosing function.

Defining a Closure Function

在上面的例子中,如果外部函数print_msg()返回值是其内部函数printer呢?

def print_msg(msg):
# This is the outer enclosing function

    def printer():
# This is the nested function
        print(msg)

    return printer  # this got changed

# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()

我们给print_msg() 函数传入了参数”Hello”,该函数返回了一个函数printer,并赋值给了another,那么another就成了一个函数,可以用another()来调用。
此时虽然print_msg()已经执行完毕,但再执行another()时,”Hello”这条消息仍然有效,“printer”这个内部“变量”也仍然有效,不会因为”离开”了其执行空间而被”销毁”导致无迹可寻。
这种技巧就叫做 Closure。
更进一步:

>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined

即使print_msg这个函数体被垃圾回收了,another以及刚才的内部变量msg仍然有效。

Closure的定义

下面三个条件都必须满足,才构成一个 Closure:

  • 有一个nested function
  • nested function 必须 refer to a value defined in the enclosing function.
  • The enclosing function must return the nested function.

Closure 的用处

  • Closure 可以减少 global value 的使用,并做到一定程度的 data hiding,提供一个 object oriented solution(面向对象的解决方案)
  • 当一个类只包含一个方法,使用 Closure 会更加 elegant。

例如:

def make_multiplier_of(n):
    e = 2
    def multiplier(x):
        return e * x * n
    return multiplier

# Multiplier of 3
times3 = make_multiplier_of(3)

# Multiplier of 5
times5 = make_multiplier_of(5)

# Output: 54
print(times3(9))

# Output: 30
print(times5(3))

# Output: 120
print(times5(times3(2)))

下一节的 Python Decorator 广泛的使用了 Closure

一些补充

所有的函数都包含一个 __closure__ 属性,如果该函数是一个 normal function,则该属性为None;如果该函数是一个 closure function,则该属性为 a tuple of cell objects。
根据上面的例子,times3times5都是 closure function

>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)

有几个内部变量就对应几个 cell

>>> times3.__closure__[0].cell_contents
3
>>> times3.__closure__[1].cell_contents
2
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值