谁能给我解释一下?关闭

Can anyone explain this to me? closure

我在阅读 realpython 中的闭包时看到了这段代码。 我真的很困惑,我不知道这些功能是什么以及它们的作用。

  1. 谁能给我解释一下吗?
  2. point.get_x, point.set_y ... 它们是什么?它们是属性吗?
>>> def make_point(x, y):
...     def point():
...         print(f"Point({x}, {y})")
...     def get_x():
...         return x
...     def get_y():
...         return y
...     def set_x(value):
...         nonlocal x
...         x = value
...     def set_y(value):
...         nonlocal y
...         y = value
...   
...     point.get_x = get_x
...     point.set_x = set_x
...     point.get_y = get_y
...     point.set_y = set_y
...     return point
...

>>> point = make_point(1, 2)
>>> point.get_x()
1
>>> point.get_y()
2
>>> point()
Point(1, 2)

>>> point.set_x(42)
>>> point.set_y(7)
>>> point()
Point(42, 7)

尽力解释—— 所以,python 中的一切都是对象,所以函数也是对象。像对象一样,您可以将属性定义为函数,例如

...     def point():
...         print(f"Point({x}, {y})")

...     point.get_x = get_x # you are setting an attribute of a function
...     point.set_x = set_x
...     point.get_y = get_y
...     point.set_y = set_y

查看属性

point = make_point(1,2)

print(point.__dict__)
{'get_x': <function make_point.<locals>.get_x at 0x000002803CA924C0>, 'set_x': <function make_point.<locals>.set_x at 0x000002803CA92040>, 'get_y': <function make_point.<locals>.get_y at 0x000002803CA92A60>, 'set_y': <function make_point.<locals>.set_y at 0x000002803CA920D0>}

您可以使用 dot 表示法访问属性。

现在要结束了,请看函数get_x

...     def get_x():
...         return x

如你所见,get_x() 不接受 x,那么它是如何知道 x 的?

print(point.get_x.__code__.co_freevars) # variables from parent scope
print(point.get_x.__code__.co_varnames) # local variables
print(point.get_x.__code__.co_names) # global variables

基本上 get_x 不知道 x,所以它检查它的父级是否有它。现在检查这个函数

def i_will_be_gone_after_call():
    name = 'fade away'
    def foo():
        print(name)
    return foo

some_var = i_will_be_gone_after_call()

# by this time i_will_be_gone_after_call call completes and popped out of call stack
some_var() # still prints `fade away` ? how
# because when defining foo, it saw that it does not know `name` variable, so it borrowed it from the parent function
# long after its parent function gone, it still remembers it and that is closure
some_var.__code__.co_freevars # ('name',)

现在来nonlocalpython2个都没有。在python 3、来到这个函数的时候

     def set_x(value):
         #nonlocal x
         x = value

当您调用此函数时 python 将创建一个局部变量 x 并为其赋值。但是你想要的是替换你提供的值 x,它在父范围内。告诉 python 使用的方法是使用 nonlocal.

def outer():
    fruit = 'apple'
    def inner():
        fruit = 'lemon'
    inner()
    print(fruit)
    return inner


outer() # --> will print apple not lemon
outer().__code__.co_varnames # ('fruit',) --> local variable, does not update fruit of outer
outer().__code__.co_freevars # ()

def outer():
    fruit = 'apple'
    def inner():
        nonlocal fruit
        fruit = 'lemon'
    inner()
    print(fruit)
    return inner


outer() # --> will print lemon
outer().__code__.co_varnames # ()
outer().__code__.co_freevars # ('fruit',) --> points to parent scope