How to create a Python decorator that can be used either with or without parameters?

前端 未结 13 1486
死守一世寂寞
死守一世寂寞 2020-11-30 21:26

I\'d like to create a Python decorator that can be used either with parameters:

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

or

相关标签:
13条回答
  • 2020-11-30 21:54

    Using keyword arguments with default values (as suggested by kquinn) is a good idea, but will require you to include the parenthesis:

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

    If you would like a version that works without the parenthesis on the decorator you will have to account both scenarios in your decorator code.

    If you were using Python 3.0 you could use keyword only arguments for this:

    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)
    

    In Python 2.x this can be emulated with varargs tricks:

    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
    

    Any of these versions would allow you to write code like this:

    @redirected_output
    def foo():
        ...
    
    @redirected_output(destination="somewhere.log")
    def bar():
        ...
    
    0 讨论(0)
提交回复
热议问题