Vad*_*aev 10 python metaprogramming
在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();
Run Code Online (Sandbox Code Playgroud)
输出是:
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()))
Run Code Online (Sandbox Code Playgroud)
为什么这样?如何更改堆栈跟踪中使用的名称?__name__那么使用的属性在哪里?
Vad*_*aev 12
所以,基本上每个函数都有三个可以被认为是函数名称的东西:
它存储在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'
Run Code Online (Sandbox Code Playgroud)
(在对问题的评论中提到的还有更多低级别的方法.)
不可变性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'
Run Code Online (Sandbox Code Playgroud)
这是pydoc输出:
FUNCTIONS
decorator1(f)
decorator2(f)
test1 = decorated(*args, **kwargs)
test2(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
由于文档中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()
Run Code Online (Sandbox Code Playgroud)
输出:
File "my.py", line 13, in <module>
name_in_module()
File "my.py", line 7, in orig_name
traceback.print_stack()
Run Code Online (Sandbox Code Playgroud)
是pydoc:
FUNCTIONS
make_function()
name_in_module = updated name()
Docstring here
Run Code Online (Sandbox Code Playgroud)
我感谢其他人的意见和答案,他们帮助我组织了我的想法和知识.