Вы только скопировали имя через функцию. Созданный объект генератора все еще использует старое имя, установленное во время компиляции.
Вам нужно будет установить это имя каждый раз, когда создается новый объект генератора; К сожалению, этот атрибут только для чтения для генераторов:
>>> 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
Название запеченный в код объекта:
>>> gen.__code__.co_name
'gen'
так что единственный способ, которым Вы можете изменить это, чтобы повторной сборки объектного кода (и расширением, функция):
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
заменить старое название:
>>> 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]
На Python 3.5, объекты генератора принимают их __name__
от а не из их объекта кода co_name
, см. issue #21205; атрибут стал доступен для записи в процессе.
Думаю, вам нужно 'functools.wraps'. Смотрите это: http://stackoverflow.com/questions/308999/what-does-functools-wraps-do/309000#309000 – Pynchia
@Pynchia: делает то же самое (плюс другие копии атрибутов). –
Я думаю, что реальный вопрос здесь * «как вы можете re'__name__' объект-генератор?» *; тот факт, что вы хотите сделать это в декораторе, является случайным. – jonrsharpe