Как создать декоратора Python, который может использоваться или с или без параметров?

Вам не нужно второе правило перезаписи.

Ваш CSS существует здесь: /css/normalize.css

Ваша страница просматривает здесь: / swift-details /2/abblinbb/css/normalize.css

Все, что вам нужно, это «передние косые черты» перед вашими дорожками CSS / JS.

70
задан elifiner 17 March 2009 в 08:10
поделиться

6 ответов

Используя споры ключевого слова со значениями по умолчанию (как предложено kquinn) хорошая идея, но потребует, чтобы Вы включали круглую скобку:

@redirect_output()
def foo():
    ...

, Если Вы хотели бы версию, которая работает без круглой скобки над декоратором, которого необходимо будет считать обоими сценариями в коде декоратора.

при использовании Python 3.0, Вы могли бы использовать ключевое слово только аргументы в пользу этого:

def redirect_output(fn=None,*,destination=None):
  destination = sys.stderr if destination is None else destination
  def wrapper(*args, **kwargs):
    ... # your code here
  if fn is None:
    def decorator(fn):
      return functools.update_wrapper(wrapper, fn)
    return decorator
  else:
    return functools.update_wrapper(wrapper, fn)

В Python 2.x это может быть эмулировано с приемами varargs:

def redirected_output(*fn,**options):
  destination = options.pop('destination', sys.stderr)
  if options:
    raise TypeError("unsupported keyword arguments: %s" % 
                    ",".join(options.keys()))
  def wrapper(*args, **kwargs):
    ... # your code here
  if fn:
    return functools.update_wrapper(wrapper, fn[0])
  else:
    def decorator(fn):
      return functools.update_wrapper(wrapper, fn)
    return decorator

Любая из этих версий позволила бы Вам писать код как это:

@redirected_output
def foo():
    ...

@redirected_output(destination="somewhere.log")
def bar():
    ...
29
ответ дан thobe 7 November 2019 в 09:25
поделиться

Декоратора Python вызывают существенно другим способом в зависимости от того, даете ли Вы ему аргументы или нет. Художественное оформление на самом деле просто (синтаксически ограничено) выражение.

В Вашем первом примере:

@redirect_output("somewhere.log")
def foo():
    ....

функция redirect_output вызвана с данным аргументом, который, как ожидают, возвратит функцию декоратора, которая саму вызвана с foo как аргумент, который (наконец!), как ожидают, возвратит финал украшенная функция.

эквивалентный код похож на это:

def foo():
    ....
d = redirect_output("somewhere.log")
foo = d(foo)

эквивалентный код для Вашего второго примера похож:

def foo():
    ....
d = redirect_output
foo = d(foo)

, Таким образом, Вы можете делать то, что Вы хотели бы, но не полностью бесшовным способом:

import types
def redirect_output(arg):
    def decorator(file, f):
        def df(*args, **kwargs):
            print 'redirecting to ', file
            return f(*args, **kwargs)
        return df
    if type(arg) is types.FunctionType:
        return decorator(sys.stderr, arg)
    return lambda f: decorator(arg, f)

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

альтернативный метод должен только потребовать, чтобы функция декоратора всегда вызывалась, даже если это без аргументов. В этом случае Ваш второй пример был бы похож на это:

@redirect_output()
def foo():
    ....

код функции декоратора был бы похож на это:

def redirect_output(file = sys.stderr):
    def decorator(file, f):
        def df(*args, **kwargs):
            print 'redirecting to ', file
            return f(*args, **kwargs)
        return df
    return lambda f: decorator(file, f)
8
ответ дан rog 7 November 2019 в 09:25
поделиться

Необходимо обнаружить оба случая, например, с помощью типа первого аргумента, и соответственно возвратить любого обертка (при использовании без параметра) или декоратор (при использовании с аргументами).

from functools import wraps
import inspect

def redirect_output(fn_or_output):
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **args):
            # Redirect output
            try:
                return fn(*args, **args)
            finally:
                # Restore output
        return wrapper

    if inspect.isfunction(fn_or_output):
        # Called with no parameter
        return decorator(fn_or_output)
    else:
        # Called with a parameter
        return decorator

При использовании @redirect_output("output.log") синтаксис, redirect_output называют с отдельным аргументом "output.log", и он должен возвратить декоратора, принимающего, что функция украшена как аргумент. При использовании в качестве @redirect_output это называют непосредственно с функцией, которая будет украшена как аргумент.

Или другими словами: @ синтаксис должен сопровождаться выражением, результатом которого является функция, принимающая, что функция украшена как собственный аргумент, и возвращающий украшенную функцию. Само выражение может быть вызовом функции, который имеет место с @redirect_output("output.log"). Замысловатый, но истинный:-)

12
ответ дан Remy Blank 7 November 2019 в 09:25
поделиться

Вы попробовали споры ключевого слова со значениями по умолчанию? Что-то как

def decorate_something(foo=bar, baz=quux):
    pass
-1
ответ дан kquinn 7 November 2019 в 09:25
поделиться

Обычно можно дать параметры по умолчанию в Python...

def redirect_output(fn, output = stderr):
    # whatever

Не уверенный, если это работает с декораторами также, все же. Я не знаю ни о какой причине, почему она не была бы.

-2
ответ дан David Z 7 November 2019 в 09:25
поделиться

Построение на ответе vartec:

imports sys

def redirect_output(func, output=None):
    if output is None:
        output = sys.stderr
    if isinstance(output, basestring):
        output = open(output, 'w') # etc...
    # everything else...
-2
ответ дан muhuk 7 November 2019 в 09:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: