类OR函数的python decorator

时间:2012-02-15 14:42:04

标签: python decorator

只是征求关于以下是否合理或是否有更好的方法的意见。基本上我想要一个将应用于函数或实现__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)

3 个答案:

答案 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,因为“显式优于隐式”。让一个装饰器完成两件事有一些概念上的开销。

(我想知道装饰器是否需要任何函数修饰器并将其转换为双重函数/类装饰器会更糟或更好......)