在Python2和Python3中,在堆栈跟踪中未使用函数的__name__
,而是使用原始名称(在def
之后指定的名称)。
考虑一下这个例子:
import traceback
def a():
return b()
def b():
return c()
def c():
print("\n".join(line.strip() for line in traceback.format_stack()))
a.__name__ = 'A'
b.__name__ = 'B'
c.__name__ = 'C'
a();
输出结果为:
File "test.py", line 16, in <module>
a();
File "test.py", line 4, in a
return b()
File "test.py", line 7, in b
return c()
File "test.py", line 10, in c
print("\n".join(line.strip() for line in traceback.format_stack()))
为什么这样?如何更改堆栈跟踪中使用的名称?那么使用__name__
属性在哪里?
答案 0 :(得分:9)
所以,基本上每个函数都有三个可以被认为是函数 name 的东西:
它存储在f.__code__.co_name
中(其中f
是函数对象)。如果您使用def orig_name
创建函数,orig_name
就是该名称。对于lambas来说,它是<lambda>
。
此属性是只读的,无法更改。因此,我知道在运行时使用自定义名称创建函数的唯一方法是exec
:
exec("""def {name}():
print '{name}'
""".format(name='any')) in globals()
any() # prints 'any'
(问题评论中提到了更多低级way to do this。)
co_name
的不变性实际上是有道理的:你可以确定你在调试器中看到的名称(或者只是堆栈跟踪)与你在源代码中看到的完全相同(以及文件名)和行号)。
__name__
属性它也是func_name
的别名。
您可以对其进行修改(orig_name.__name__ = 'updated name'
)并确实每天都会进行修改:@functools.wraps
将已修饰函数的__name__
复制到新版本。
__name__
这样的工具使用 pydoc
,这就是您需要@functools.wraps
的原因:所以您没有看到文档中每个装饰器的技术细节。看一下这个例子:
from functools import wraps
def decorator1(f):
def decorated(*args, **kwargs):
print 'start1'
f(*args, **kwargs)
return decorated
def decorator2(f):
@wraps(f)
def decorated(*args, **kwargs):
print 'start2'
f(*args, **kwargs)
return decorated
@decorator1
def test1():
print 'test1'
@decorator2
def test2():
print 'test2'
以下是pydoc
输出:
FUNCTIONS
decorator1(f)
decorator2(f)
test1 = decorated(*args, **kwargs)
test2(*args, **kwargs)
使用wraps
时,文档中没有decorated
的迹象。
可以称为函数名称的另一件事(虽然它几乎不是)是存储对该函数的引用的变量或属性的名称。
如果使用def name
创建函数,name
属性将添加到当前范围。如果是lambda
,您应该将结果分配给某个变量:name = lambda: None
。
显然,您可以为同一个函数创建多个引用,并且所有引用都可以有不同的名称。
这三件事彼此连接的唯一方法是def foo
语句创建函数对象,__name__
和__code__.co_name
等于foo
并分配它到当前范围的foo
属性。但它们不受任何方式的束缚,可能彼此不同:
import traceback
def make_function():
def orig_name():
"""Docstring here
"""
traceback.print_stack()
return orig_name
globals()['name_in_module'] = make_function()
name_in_module.__name__ = 'updated name'
name_in_module()
输出:
File "my.py", line 13, in <module>
name_in_module()
File "my.py", line 7, in orig_name
traceback.print_stack()
是pydoc:
FUNCTIONS
make_function()
name_in_module = updated name()
Docstring here
我感谢其他人的意见和答案,他们帮助我组织了我的想法和知识。
答案 1 :(得分:3)
试图探索enter image description here实施,绝对不是专家。正如评论中所指出的,当打印f的堆栈条目时,属性f.__code__.co_name
CPython。此外,f.__name__
is used至f.__code__.co_name
,is initially set前者,后者未相应修改。
因此,我试图直接修改它,但不可能:
>>> f.__code__.co_name = 'g'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
>>>
为什么有两种方式来说出一个功能的名字?好吧,but when you modify,__name__
是为&#34;类,函数,方法,描述符或生成器实例&#34;定义的,因此在函数的情况下,它映射到该属性,对于其他对象它将映射到其他东西。