Python decorator (закрывающая версия), который сохраняет подпись - PullRequest
0 голосов
/ 05 октября 2018

Мой декоратор "в стиле закрытия";он выполняет некоторую работу перед возвратом декорированной функции.

Заимствование из этого известного вопроса: Сохранение подписей декорированных функций

def args_as_ints(f):

    time.sleep(1) # hard at work

    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)
    return g

functools.wraps не сохраняет сигнатурув Python 2.

from functools import wraps

def args_as_ints(f):

    time.sleep(1) # hard at work

    @wraps(f) 
    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)
    return g


@args_as_ints
def funny_function(x, y, z=3):
    """Computes x*y + 2*z"""
    return x*y + 2*z

help(funny_function)

показывает

Help on function funny_function in module __main__:

funny_function(*args, **kwargs)
    Computes x*y + 2*z

Модуль decorator, похоже, не поддерживает этот стиль декоратора.

Также связано: Сохранить подпись в Python Decorator 2

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Удалось найти ответ здесь: https://decorator.readthedocs.io/en/latest/tests.documentation.html#dealing-with-third-party-decorators

def args_as_ints(f):

    time.sleep(1)

    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)

    return decorator.FunctionMaker.create(
        f, 'return decfunc(%(signature)s)',
        dict(decfunc=g, __wrapped__=f))
0 голосов
/ 05 октября 2018

Вы можете использовать модуль wrapt.

Имейте в виду, что декораторы wrapt имеют интерфейс, отличный от стандартных декораторов python.Я настоятельно рекомендую прочитать документацию wrapt .В любом случае, вот базовая реализация вашего декоратора с wrapt.decorator:

import wrapt

def args_as_ints(f):
    time.sleep(1) # hard at work

    @wrapt.decorator
    def g(f, instance, *args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)

    return g(f)  # apply the decorator to the function

Обратите внимание, что моя реализация полностью игнорирует аргумент instance, поэтому он не будет работать правильно для методов экземпляра.

Однако он поддерживает подпись оформленной функции:

Help on function funny_function in module __main__:

funny_function(x, y, z=3)
    Computes x*y + 2*z
...