python decorator for class methods
我有一个装饰器来注册一些类方法。如何正确获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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() |
回溯(最近一次呼叫的最后一次):
1 | TypeError: wrapper() got multiple values for keyword argument 'run' |
你的问题与装修工无关。简单来说:你所做的是:
1 2 3 4 | def foo(run=False, *args, **kwargs): print(run, args, kwargs) foo(1, 2, run=True) # TypeError: foo() got multiple values for argument 'run' |
从函数签名中,python将尝试设置
一个解决方法-虽然不是很好-可能是:
1 2 3 | def foo(*args, **kwargs): run = kwargs.pop('run', False) # run defaults to False; remove from kwargs print(run, args, kwargs) |
python3的参数似乎更合适,但不知道如何在python2中做到这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
run参数来自fun,请尝试从函数的参数中获取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 |