Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 更改生成器的名称_Python_Python 2.7_Generator - Fatal编程技术网

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]