gpt4 book ai didi

python - 如何在声明中找到 python 函数的名称引用?

转载 作者:太空宇宙 更新时间:2023-11-04 10:28:50 25 4
gpt4 key购买 nike

foo 完全出乎意料(至少对我而言)会知道foo函数内部 def对于 foo .这到底是怎么回事?

>>> def foo(x):
... print "wow"
... print globals().get('foo', 'sorry')
... return foo
...
>>> f = foo(3)
wow
<function foo at 0x10135f8c0>
>>> f
<function foo at 0x10135f8c0>

这是 python 惰性求值的某种影响吗?它首先构建函数代码并将其放入 globals 中,但实际上是在稍后调用时构建该函数?哇...这是什么形式的 python 魔法?

当然,这使得递归变得容易......并且可能是这在语言中的原因......

>>> def bar(x):
... return bar(x)
...
>>> bar(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in bar
File "<stdin>", line 2, in bar
File "<stdin>", line 2, in bar
...snip...
File "<stdin>", line 2, in bar
File "<stdin>", line 2, in bar
RuntimeError: maximum recursion depth exceeded

最佳答案

也许 dis 可以帮助...

>>> def foo(x):
... print "wow"
... print globals().get('foo', 'sorry')
... return foo
...
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_CONST 1 ('wow')
3 PRINT_ITEM
4 PRINT_NEWLINE

3 5 LOAD_GLOBAL 0 (globals)
8 CALL_FUNCTION 0
11 LOAD_ATTR 1 (get)
14 LOAD_CONST 2 ('foo')
17 LOAD_CONST 3 ('sorry')
20 CALL_FUNCTION 2
23 PRINT_ITEM
24 PRINT_NEWLINE

4 25 LOAD_GLOBAL 2 (foo)
28 RETURN_VALUE
>>>

嗯。复杂的。所以让我们更简单...

>>> def zap(x):
... return zap
...
>>> dis.dis(zap)
2 0 LOAD_GLOBAL 0 (zap)
3 RETURN_VALUE
>>>

是的,看起来字节码已构建,并包含从 globals 加载 zap 的指令。因此,两步过程使得 zap 内部的 zap 根本不是什么特别的东西。

让我们看看是否可以更好地深入研究过程并阐明...

>>> def blah(x):
... def hlab(y):
... return blah(x)
... return hlab
...
>>> blah.func_code.co_consts
(None, <code object hlab at 0x10fcdfd30, file "<stdin>", line 2>)
>>> b = blah(4)
>>> b
<function hlab at 0x10fce9c80>
>>> dis.dis(blah.func_code.co_consts[-1])
3 0 LOAD_GLOBAL 0 (blah)
3 LOAD_DEREF 0 (x)
6 CALL_FUNCTION 1
9 RETURN_VALUE
>>> dis.dis(b)
3 0 LOAD_GLOBAL 0 (blah)
3 LOAD_DEREF 0 (x)
6 CALL_FUNCTION 1
9 RETURN_VALUE
>>> b_ = blah.func_code.co_consts[-1]
>>> b.func_code
<code object hlab at 0x10fcdfd30, file "<stdin>", line 2>
>>> b_
<code object hlab at 0x10fcdfd30, file "<stdin>", line 2>
>>>

所以看起来字节码是先构建的,然后函数是从那个构建的……然后指向原始字节码。我仍然不明白它是如何连接起来的,但我认为这是在“堆栈”上以某种方式完成的。至少,这个过程将使函数 def 中使用的任何名称引用都变得不特殊(即,如果 foo 使用 fooblah随便)。

好的,我明白了。没什么特别的。

虽然这有点奇怪......

>>> b(2)
<function hlab at 0x10faf9410>
>>> b(2)(2)
<function hlab at 0x10faf9578>
>>> b(2)(2)(2)
<function hlab at 0x10faf9410>
>>> _ is b(2)
False

...但我假设它只是循环可用的内存地址,或类似的东西。

关于python - 如何在声明中找到 python 函数的名称引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28129057/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com