factorial
在你的第一个例子中是一个全局函数。您递归调用它的事实并没有改变,您仍然首先需要查找函数对象才能调用它。
换句话说,当前被调用的函数没有任何特殊之处。factorial
仍然是一个需要取消引用的名称,并且该名称恰好引用了正在执行的函数并不重要。
因此,在您的第二个示例中, wherefactorial
是一个方法,没有对该方法的全局引用。相反,您可以通过self
引用找到它与类上的任何其他方法一样。
当您定义一个函数时,Python 会在当前范围内以您给它的名称存储对该新函数对象的引用。在全局范围内,这意味着它def foo()
成为foo
绑定到函数对象的全局名称。您可以通过删除该名称来中断递归:
>>> def foo(): return foo() # infinite recursion
...
>>> def foo(): return foo() # infinite recursion
...
>>> foo
<function foo at 0x108e4b500>
>>> bar = foo
>>> del foo
>>> foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> bar
<function foo at 0x108e4b500>
>>> bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in foo
NameError: global name 'foo' is not defined
注意NameError
这里;我从全局命名空间中删除foo
了,但仍然有一个引用bar
,我可以调用它。但是函数本身在执行时找不到全局名称foo
。
否则,Python 函数不会引用它们自己。从函数内部,您不能可靠地检索函数对象本身。您可以做的最好的事情是获取原始函数名称:
>>> def foo():
... return sys._getframe(0).f_code.co_name
...
>>> foo()
'foo'
>>> bar = foo
>>> bar()
'foo'
但这并不能保证您仍然可以通过该名称访问该函数对象。