python会搞坏电脑吗_Python如何破坏垃圾?

我对这个简单功能的行为有疑问。这里是一个代码:

def foo():

pi = 3.14

def f():

return pi

return f

F = foo()

F() # this is returning the 3.14

为什么函数f返回3.14?我以为,执行完函数后整个本地名称空间应该销毁,不是吗?那么,最后的函数foo返回指向已声明函数的指针f(该函数将被分配到堆中),但是变量pi必须销毁为堆栈变量吗?

解决方案

为什么函数f返回3.14?我以为,执行完函数后整个本地名称空间应该销毁,不是吗?

是的,没有。

在这种情况下,本地名称空间中所需的变量将保留为本地定义函数的所谓“关闭”。在这种情况下,pi直到需要该变量为止,该变量才可用于该功能。

让我们详细说明一下:

def foo():

pi = 3.14

def f():

return pi

return f

这是外部功能。

在CLI中,我们可以进行一些操作。

>>> foo

>>> dir(foo)

['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

啊,有个类似__closure__的词,我刚才用过的。它是什么?

>>> foo.__closure__

>>>

??

>>> foo.__closure__ is None

True

啊。

>>> f = foo() # get the inner function

>>> f

.f at 0x000001B4E5C6C158>

>>> f()

3.14

好。让我们看看它里面有什么:

>>> f.__closure__

(,)

那是什么

>>> c = f.__closure__[0]

>>> c

一个细胞?

>>> dir(c)

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']

>>> c.cell_contents

3.14

啊。所以f.__closure__[0]是一种细胞,就像一个容器,从本地命名空间上面获取的值。

另外,我们可以研究一下函数的反汇编:

>>> import dis

>>> dis.dis(foo)

2 0 LOAD_CONST 1 (3.14)

2 STORE_DEREF 0 (pi)

3 4 LOAD_CLOSURE 0 (pi)

6 BUILD_TUPLE 1

8 LOAD_CONST 2 (", line 3>)

10 LOAD_CONST 3 ('foo..f')

12 MAKE_FUNCTION 8

14 STORE_FAST 0 (f)

5 16 LOAD_FAST 0 (f)

18 RETURN_VALUE

>>> dis.dis(f)

4 0 LOAD_DEREF 0 (pi)

2 RETURN_VALUE

在这里,我们看到如何f构造:

3 4 LOAD_CLOSURE 0 (pi)

将变量加载pi为闭包(单元格)

6 BUILD_TUPLE 1

只用这个单元格建立一个元组

8 LOAD_CONST 2 (", line 3>)

10 LOAD_CONST 3 ('foo..f')

12 MAKE_FUNCTION 8

使用给定的名称,代码和闭包创建函数

14 STORE_FAST 0 (f)

储存它。

在函数中,使用来访问闭包元素LOAD_DEREF。

如果我们稍微扩展一下功能,例如

def foo():

pi = 3.14

two = 2

three = 3

def f():

return pi - three

return f

我们看到如何处理和处理这些变量:

>>> dis.dis(foo)

2 0 LOAD_CONST 1 (3.14)

2 STORE_DEREF 0 (pi)

3 4 LOAD_CONST 2 (2)

6 STORE_FAST 0 (two)

4 8 LOAD_CONST 3 (3)

10 STORE_DEREF 1 (three)

5 12 LOAD_CLOSURE 0 (pi)

14 LOAD_CLOSURE 1 (three)

16 BUILD_TUPLE 2

18 LOAD_CONST 4 (", line 5>)

20 LOAD_CONST 5 ('foo..f')

22 MAKE_FUNCTION 8

24 STORE_FAST 1 (f)

7 26 LOAD_FAST 1 (f)

28 RETURN_VALUE

查看变量pi和three与two:的区别two是如何与一起存储STORE_FAST,其他变量则使用STORE_DEREF它们,以便可以将其传递给函数。

>>> foo().__closure__

(, )

现在,它具有两个元素:

>>> foo().__closure__[0].cell_contents

3.14

>>> foo().__closure__[1].cell_contents

3

这是它的用法:

>>> dis.dis(f)

6 0 LOAD_DEREF 0 (pi)

2 LOAD_DEREF 1 (three)

4 BINARY_SUBTRACT

6 RETURN_VALUE

减法确实发生在内部函数内部,因为变量甚至可能会更改:

import time

import threading

def foo():

c = 0

def run():

nonlocal c

while c < 50:

c += 1

time.sleep(1.0)

t = threading.Thread(target=run)

t.start()

def f(): return c

return f

在这里,线程每秒增加一次变量。如果现在执行f = foo(),我们将获得此内部函数,如果多次调用且两次调用之间有一段时间,则该函数将返回不同的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值