Python 更改生成器的名称
给定以下设置:Python 更改生成器的名称,python,python-2.7,generator,Python,Python 2.7,Generator,给定以下设置: def mapper(f): def wrapper(items): for x in items: yield f(x) wrapper.__name__ = f.__name__ # This has no effect! return wrapper @mapper def double(x): return x * 2 装饰师按预期工作: >>> [x for x in doub
def mapper(f):
def wrapper(items):
for x in items:
yield f(x)
wrapper.__name__ = f.__name__ # This has no effect!
return wrapper
@mapper
def double(x):
return x * 2
装饰师按预期工作:
>>> [x for x in double([1,2,3])]
[2, 4, 6]
但是,其\uuuu名称\uuuuu
不是所需的double
:
>>> double([1,2]).__name__
"wrapper"
是否可以强制输入生成器的名称?
或者,是否可以在generator对象中搜索并检索名称
double
?您只将名称复制到函数中。生成的生成器对象仍然使用编译时设置的旧名称
每次生成新的生成器对象时,都必须设置该名称;不幸的是,对于生成器,该属性是只读的:
>>> def gen():
... yield None
...
>>> gen().__name__
'gen'
>>> gen().__name__ = 'foo'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: attribute '__name__' of 'generator' objects is not writable
因此,唯一可以改变这一点的方法是重新构建代码对象(扩展为函数):
这将创建一个新函数和代码对象,使用new\u name
替换旧名称:
>>> new_name = rename_code_object(gen, 'new_name')
>>> new_name.__name__
'new_name'
>>> new_name().__name__
'new_name'
>>> new_name()
<generator object new_name at 0x10075f280>
演示:
def映射器(f):
... def包装(项目):
... 对于项目中的x:
... 收益率f(x)
... 返回重命名\u代码\u对象(包装器,f.\u名称\u)
...
>>>@mapper
... 双def(x):
... 返回x*2
...
>>>双([1,2])
>>>列表(双([1,2]))
[2, 4]
从Python3.5开始,生成器对象从函数对象而不是从其代码对象
co\u name
属性获取\uu名称
,请参见;该属性在此过程中变为可写。我认为您需要functools.wrapps
。看到这个:@Pynchia:which做完全相同的事情(加上其他属性副本)。我认为这里真正的问题是“如何重新生成生成器对象?”;您希望在decorator中这样做的事实是偶然的。谢谢@jornsharpe,我已经修改了标题。嗨@Scott,更改生成器的名称只是达到目的的一种方法:通过decorator转换时保留函数名。(我的示例旨在提出一个合理的用例。)不幸的是,当您调用它时,这会引发一个错误:AttributeError:attribute'\uu name\uuuuuu'的“generator”对象是不可写的-P@MartijnPieters这不会有太大帮助,因为gi\u code
也是只读的。也许有人可以用eval()做一些(可怕的)事情。这确实可怕,但这正是我想要的!谢谢@MartijnPieters:)
def rename_code_object(func, new_name):
code_object = func.__code__
function, code = type(func), type(code_object)
return function(
code(
code_object.co_argcount, code_object.co_nlocals,
code_object.co_stacksize, code_object.co_flags,
code_object.co_code, code_object.co_consts,
code_object.co_names, code_object.co_varnames,
code_object.co_filename, new_name,
code_object.co_firstlineno, code_object.co_lnotab,
code_object.co_freevars, code_object.co_cellvars),
func.__globals__, new_name, func.__defaults__, func.__closure__)
>>> new_name = rename_code_object(gen, 'new_name')
>>> new_name.__name__
'new_name'
>>> new_name().__name__
'new_name'
>>> new_name()
<generator object new_name at 0x10075f280>
def mapper(f):
def wrapper(items):
for x in items:
yield f(x)
return rename_code_object(wrapper, f.__name__)
>>> def mapper(f):
... def wrapper(items):
... for x in items:
... yield f(x)
... return rename_code_object(wrapper, f.__name__)
...
>>> @mapper
... def double(x):
... return x * 2
...
>>> double([1, 2])
<generator object double at 0x10075f370>
>>> list(double([1, 2]))
[2, 4]