문제

내가 하려고 했 쓰기 장식 기능을 감싸는 asyncio.coroutine 고 반환하는 데 걸린 시간입니다.레시피 아래 코드가 포함되어 있는 작업으로 나는 예상된다.나만 문제는 그것으로 어떻게든 내가 느슨한의 이름을 장식 기능의 사용에도 불구하고 @functools.wraps.을 유지하는 방법의 이름이 원래 coroutine?체크의 원 asyncio.

import asyncio
import functools
import random
import time

MULTIPLIER = 5

def time_resulted(coro):
    @functools.wraps(coro)
    @asyncio.coroutine
    def wrapper(*args, **kargs):
        time_before = time.time()
        result = yield from coro(*args, **kargs)
        if result is not None:
            raise TypeError('time resulted coroutine can '
                'only return None')
        return time_before, time.time()
    print('= wrapper.__name__: {!r} ='.format(wrapper.__name__))
    return wrapper

@time_resulted
@asyncio.coroutine
def random_sleep():
    sleep_time = random.random() * MULTIPLIER
    print('{} -> {}'.format(time.time(), sleep_time))
    yield from asyncio.sleep(sleep_time)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    tasks = [asyncio.Task(random_sleep()) for i in range(5)]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()
    for task in tasks:
        print(task, task.result()[1] - task.result()[0])
    print('= random_sleep.__name__: {!r} ='.format(
        random_sleep.__name__))
    print('= random_sleep().__name__: {!r} ='.format(
        random_sleep().__name__))

결과:

= wrapper.__name__: 'random_sleep' =
1397226479.00875 -> 4.261069174838891
1397226479.00875 -> 0.6596335046471768
1397226479.00875 -> 3.83421163259601
1397226479.00875 -> 2.5514027672929713
1397226479.00875 -> 4.497471439365472
Task(<wrapper>)<result=(1397226479.00875, 1397226483.274884)> 4.266134023666382
Task(<wrapper>)<result=(1397226479.00875, 1397226479.6697)> 0.6609499454498291
Task(<wrapper>)<result=(1397226479.00875, 1397226482.844265)> 3.835515022277832
Task(<wrapper>)<result=(1397226479.00875, 1397226481.562422)> 2.5536720752716064
Task(<wrapper>)<result=(1397226479.00875, 1397226483.51523)> 4.506479978561401
= random_sleep.__name__: 'random_sleep' =
= random_sleep().__name__: 'wrapper' =

당신이 볼 수 있습니다 random_sleep() 반환 개체 발전기와 다른 이름입니다.고 싶지의 이름을 장식 coroutine.저는 알지 못하는 경우 이 문제는 특정 asyncio.coroutines 나지 않습니다.저는 코드는 다른 장식을 주문 하지만 모두 같은 결과입니다.면 내가 코멘트 @functools.wraps(coro)random_sleep.__name__wrapper 로 예상된다.

편집:나는 게시된 이 문제를 Python 문제를 추적하고를 받은 다음에 의하여 응답 R.데이비드 머레이:"나는 생각에 이것은 특정한 경우의 일반적인 개선이 필요한'랩'을 논의에 python-dev 너무 오래 전에."

도움이 되었습니까?

해결책

문제는 functools.wraps 만 변경 wrapper.__name__wrapper().__name__ 숙박 wrapper. __name__ 은 읽기 전용 발전기 속성이 있습니다.당신이 사용할 수 exec 을 설정하는 적당한 이름:

import asyncio
import functools
import uuid
from textwrap import dedent

def wrap_coroutine(coro, name_prefix='__' + uuid.uuid4().hex):
    """Like functools.wraps but preserves coroutine names."""
    # attribute __name__ is not writable for a generator, set it dynamically
    namespace = {
        # use name_prefix to avoid an accidental name conflict
        name_prefix + 'coro': coro,
        name_prefix + 'functools': functools,
        name_prefix + 'asyncio': asyncio,
    }
    exec(dedent('''
        def {0}decorator({0}wrapper_coro):
            @{0}functools.wraps({0}coro)
            @{0}asyncio.coroutine
            def {wrapper_name}(*{0}args, **{0}kwargs):
                {0}result = yield from {0}wrapper_coro(*{0}args, **{0}kwargs)
                return {0}result
            return {wrapper_name}
        ''').format(name_prefix, wrapper_name=coro.__name__), namespace)
    return namespace[name_prefix + 'decorator']

사용법:

def time_resulted(coro):
    @wrap_coroutine(coro)
    def wrapper(*args, **kargs):
        # ...
    return wrapper

그것은 작동하지만 아마 더 나은 방법을 사용하는 것보다 exec().

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top