Плохо ли использовать себя в декораторах? - PullRequest
5 голосов
/ 03 сентября 2010

Хотя я знаю, что вы не можете ссылаться на self непосредственно в декораторе, мне было интересно, если это плохая практика, обойти это, вытаскивая его из args[0].Я догадываюсь, что это так, но я хочу быть уверенным.

Если говорить более конкретно, я работаю над API для веб-службы.Около половины команд требуют передачи токена, который впоследствии можно будет использовать для его отмены.Я хотел бы сделать этот токен необязательным параметром и, если он не указан, сгенерировать его.Генерация токена требует выполнения аутентифицированного вызова к серверу, который требует данных от объекта.

Хотя я знаю, что мог бы сделать это:

def some_command(self, ..., undo_token = None):
    if undo_token = None:
        undo_token = self.get_undo_token()
    ...
    return fnord

Я чувствую, что могло бы быть лучшечем иметь один и тот же код в дюжине или около того методов.Я думал написать декоратор:

@decorator
def undoable(fn, *args, **kwargs):
    if 'undo_token' not in kwargs:
        kwargs['undo_token'] = args[0].get_undo_token()
    return (fn(*args, **kwargs), kwargs['undo_token'])

Так что я могу написать более аккуратно

@undoable
def some_command(self, ...):
    ...
    return foo

@undoable
def some_other_command(self, ...):
    ...
    return bar

Я готовлюсь к неприятностям в будущем?

Ответы [ 2 ]

6 голосов
/ 03 сентября 2010

Я не понимаю, что вы кодируете для undoable - это не то, как обычно кодируются декораторы, и я не знаю, откуда исходит @decorator (есть from youforgottotelluswhence import decorator или что-то ещёбольше зла? понимаете, почему я не могу использовать from для создания "искусственных голых имен" вместо того, чтобы использовать красивые украшенные имена?...:

import functools

def undoable(f):
    @functools.wraps(f)
    def wrapper(self, *a, **k):
        tok = k.get('undo_token')
        if tok is None:
            tok = k['undo_token'] = self.get_undo_token()
        return f(self, *a, **k), tok
    return wrapper

нет абсолютно никаких проблем с наименованием первого, обязательного позиционного аргумента оболочки self, и большая польза для ясности в использовании этого, а не менее читаемого args[0].

2 голосов
/ 03 сентября 2010

Декораторы расширяют функциональность функции, которую он декорирует, в общем виде.Если декораторы не делают каких-либо предположений относительно функции или ее аргументов или kwargs, она имеет наиболее общую форму и может быть легко использована со многими функциями.

Как бы то ни было, если вы хотите что-то сделать с тем, чтоПередача в функцию должна быть в порядке, но их применимость ограничена и может сломаться, если изменится базовая информация, которую вы использовали в декораторе.

В вышеприведенном декораторе, если объект удаляет метод get_undo_token (), вам необходимо также вернуться к декоратору.Это хорошо, но документируйте ограничения, а также добавьте эту документацию к самому методу.

Делайте это только в случае крайней необходимости.Он служит для создания более общих декораторов.

...