装饰器调用没有类实例化的类方法?

时间:2020-01-02 15:25:38

标签: python decorator

在下面的代码中,我为类Class方法创建了一个装饰器。我注意到,即使不创建类实例也将调用此装饰器! 而且无需在类中调用这些方法!

对此有什么解释吗?

装饰器:

def deco(class_name):
    def inner_function(method):
        print("method is = {} and class is: {}".format(method.__name__,class_name.__name__))
        return method
    return inner_function

class_deco

class class_deco :
    def __init__(self):
        pass

班级:

class Class :
    def __init__(self):
       pass

    @deco(class_deco)
    def f1(self):
        pass

    @deco(class_deco)
    def f2(self):
        pass

当我运行脚本时:

if __name__ == "__main__":
    pass

我得到这个结果:

method is = f1 and class is: class_deco
method is = f2 and class is: class_deco

3 个答案:

答案 0 :(得分:2)

装饰者只是以下人群的合成糖

@deco(class_deco)
def f1(self):
    pass

与-

相同
f1 = deco(class_deco)(f1)

因此,该代码在导入模块后立即运行,就像其他任何名称声明一样,并且f1名称如上所述被修饰的f1替换。

答案 1 :(得分:2)

如前所述,@decorator语法只是语法糖,因此:

@somedecorator
def foo():
    pass

严格等同于

def foo():
    pass

foo = somedecorator(foo)

在这种情况下,您将显式调用装饰器函数:

@deco(class_deco)
def f1(self):
    pass

等效于:

def f1(self):
    pass

 _effective_decorator = deco(class_deco)

 f1 = _effective_decorator(f1)

这就是为什么inner_function确实在导入时执行的原因。

采用其他参数的装饰器需要多层嵌套,因此从技术上讲,装饰器应如下所示:

def deco(cls):
    def real_deco(func):
        def inner_function(*args, **kw):
            print("method is = {} and class is: {}".format(func.__name__,cls.__name__))
            return func(*args, **kw)
        return inner_function
    return real_deco
return inner_function

但是如果要获取方法确实所属的类的名称,这仍然是无效的-您应该从调用该方法的实例中获取该类,而不是尝试在装饰器调用中对其进行硬编码(这将永远无法按预期工作,因为在将装饰器应用于函数时,实际类并不存在)。因此正确的实现应类似于:

def deco(func):
    # we're only supposed to use this on methods...
    def wrapper(self, *args, **kw):
        print("class {} - method {}".format(type(self).__name__, func.__name__))

    return wrapper


class Class:
    @deco
    def f1(self):
        pass

注意:这当然不会处理类方法或静态方法。

答案 2 :(得分:1)

这里是一个演示,展示了仅两种可能的构造装饰器的方式:


def Deco(*deco_params):
    print('In Deco', deco_params)
    def deco(func):
        print('In deco(func)')
        def inner(*args, **kwargs):
            print('In inner(*args, **kwargs)')
            return func(*args, **kwargs)
        return inner
    return deco

def deco(method):
    print('In deco(method)')
    def inner_function(*args, **kwargs):
        print("method is = {} called".format(method.__name__))
        return method(*args, **kwargs)
    return inner_function


class Class :
    def __init__(self):
       pass

    @deco
    def f1(self):
        pass

    @Deco(42)
    def f2(self):
        pass

if __name__ == "__main__":
    print('Now in Main')
    c = Class()
    c.f1()
    c.f2()

输出:

In deco(method)
In Deco (42,)
In deco(func)
Now in Main
method is = f1 called
In inner(*args, **kwargs)