至少在我看来,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

最佳答案

没有什么真正的神秘。

我认为这有两个方面,您正在对该函数主体进行后期评估。

更新:我对解释定义步骤之后发生的情况进行了解释-看起来函数代码在调用之前确实发生了某些事情。在这方面,沃利的答案比我的要好。

通过#1-找到def foo(x)并在模块的命名空间上进行设置。可能还会添加功能参数。

仅此而已,您无需深入研究代码。

更新:实际上,我不确定在调用之前是否以某种方式处理了代码。查看foo.func_code内部,在调用之前和之后都没有太大区别。

另外,如果您遇到语法错误(如括号嵌套或空格问题),甚至在调用该函数之前就出现了,因此在调用之前会先进行一些处理。最终请参阅我的代码。

我猜想代码已经解析了,但是任何变量解析都会推迟到实际执行为止。

传递#2-您调用foo(x),找到并调用了它。

该函数的代码是第一次执行。

当您点击globals()[“ foo”]时,它将获取存储在#1中的现有引用。

当您运行coverage.py或类似内容时,您还可以看到一些有关此行为的提示。导入时,模块中的所有外部定义都标记为已覆盖。

但是实际的代码仅在您调用它时被覆盖。

另一种思考的方式是,您需要先通过命名空间来设置引用,然后再继续。否则,在下面的代码中,foo将找不到bar。

这是我用来区分执行错误与语法错误的一些代码...

def foo(x):
    """comment/uncomment to see behavior"""
    pass
    # return bar(x)   #this works

    return bar2(x)  #call time error

    #   return bar(x) bad whitespace  #IndentationError, nothing runs

print "foo defined"

def bar(x):
    return x*2


print "calling foo#1"

try:
    print foo(3)
except Exception, e:
    print e

#let's make it so there is a bar2...
bar2 = bar

print "calling foo#2"

try:
    print foo(6)
except Exception, e:
    print e

07-24 18:40
查看更多