只是征求关于以下是否合理或是否有更好的方法的意见。基本上我想要一个将应用于函数或实现__call __。
的类的装饰器你可以只有一个普通的装饰器并明确地装饰__call__但是装饰器隐藏在类定义中并且不太明显。也许我错过了一个更简单的解决方案。
import types
from functools import wraps
class dec:
""" Decorates either a class that implements __call__
or a function directly.
"""
def __init__(self, foo):
self._foo = foo
def __call__(self, target):
wraps_class = isinstance(target, types.ClassType)
if wraps_class:
fun = target.__call__
else:
fun = target
@wraps(fun)
def bar(*args, **kwds):
val = args[1] if wraps_class else args[0]
print self._foo, val
return fun(*args, **kwds)
if wraps_class:
target.__call__ = bar
return target
else:
return bar
@dec('A')
class a:
# you could decorate here, but it seems a bit hidden
def __call__(self, val):
print "passed to a:", val
@dec('B')
def b(val):
print "passed to b:", val
a()(11)
b(22)
答案 0 :(得分:4)
就个人而言,我会把它分成两个装饰器:一个总是包装一个函数:
def func_dec(foo, is_method=False):
def wrapper(fun):
@wraps(fun)
def bar(*args, **kwds):
val = args[1] if is_method else args[0]
print foo, val
return fun(*args, **kwds)
return bar
return wrapper
另一个检测是否应该修改__call__
方法或简单地包装函数:
def dec(foo):
def wrapper(obj):
if inspect.isclass(obj):
obj.__call__ = func_dec(foo, is_method=True)(obj.__call__)
return obj
else:
return func_dec(foo)(obj)
return wrapper
请注意inspect.isclass
对于旧式和新式类都会正常运行。
答案 1 :(得分:3)
我真的不喜欢你的做法。如果调用实例,则使用__call__()
方法。调用类本身会调用__init__()
,所以我不认为这是非常类似的。
您的装饰器不适用于新式类(直接或间接派生自object
)。如果这是您想要的,请自己帮忙并简单地装饰__call__()
。或者编写一个工厂函数来创建和修饰类的实例 - 这完全类似于装饰函数,因为实例可以直接调用,而且你不必乱用arounf self
参数。
答案 2 :(得分:1)
这是一个非常漂亮的想法。这对我来说似乎很好,虽然直接装饰__call__
可能更加pythonic,因为“显式优于隐式”。让一个装饰器完成两件事有一些概念上的开销。
(我想知道装饰器是否需要任何函数修饰器并将其转换为双重函数/类装饰器会更糟或更好......)