首页 文章

类方法的python装饰器

提问于
浏览
1

我有一个装饰器来注册一些类方法 . 如何正确获取 selfrun 参数?

class Task(object):
    _tasks = []

    @staticmethod
    def register(name):
        def decorator(fn):
            @wraps(fn)
            def wrapper(self=None, run=True, *args, **kwargs):
                if not run:
                    task = defaultdict()
                    task['name'] = name
                    task['fn'] = getattr(self, fn.__name__, None)
                    task['obj'] = self
                    task['args'] = deepcopy(args)
                    task['kwargs'] = deepcopy(kwargs)
                    Task._tasks.append(task)
                else:
                    return fn(self, *args, **kwargs)
            return wrapper
        return decorator

class Test(object):
    def __init__(self, name):
        self.name = name

    @Task.register('foo')
    def foo(self, v1, v2):
        print 'running foo in object {} with arguments {} {}'.format(self.name, v1, v2)

    @Task.register('hello')
    def hello(self):
        print 'running hello in object {} '.format(self.name)

    def load(self):
        self.foo('1', '2', run=False)
        self.hello(run=False)

t1=Test('t1')
t1.load()

回溯(最近的呼叫最后):

TypeError: wrapper() got multiple values for keyword argument 'run'

3 回答

  • 0

    Python3似乎有更好的参数,但不知道如何在python2中执行此操作:

    from functools import wraps
    def optional_debug(func):
        @wraps(func)
        def wrapper(*args, debug=False, **kwargs):
            if debug:
                print('Calling', func.__name__)
            return func(*args, **kwargs)
        return wrapper
    
    @optional_debug
    def spam(a,b,c):
        print(a,b,c)
    
    spam(1,2,3)         # 1,2,3
    
    spam(1,2,3, debug=True)    # Calling spam    # 1 2 3
    
  • 0

    run参数来自fun,所以尝试从函数的参数中获取它:

    from collections import defaultdict
    from copy import deepcopy
    from functools import wraps
    
    class Task(object):
        _tasks = []
    
        @staticmethod
        def register(name):
            def decorator(fn):
                @wraps(fn)
                def wrapper(self=None, *args, **kwargs):
                    run = kwargs.pop('run', True)
                    if not run:
                        task = defaultdict()
                        task['name'] = name
                        task['fn'] = getattr(self, fn.__name__, None)
                        task['obj'] = self
                        task['args'] = deepcopy(args)
                        task['kwargs'] = deepcopy(kwargs)
                        Task._tasks.append(task)
                    else:
                        return fn(self, *args, **kwargs)
    
                return wrapper
    
            return decorator
    
  • 0

    你的问题与装饰者无关 . 以更简单的形式:你在做什么是这样的:

    def foo(run=False, *args, **kwargs):
        print(run, args, kwargs)
    
    foo(1, 2, run=True)  # TypeError: foo() got multiple values for argument 'run'
    

    从你的函数签名,python将尝试设置 run=1args = (2,) 然后运行 TypeError .

    一个修复 - 虽然不是一个非常好的 - 可能是:

    def foo(*args, **kwargs):
        run = kwargs.pop('run', False)  # run defaults to False; remove from kwargs
        print(run, args, kwargs)
    

相关问题