在没有类实例化的情况下调用类方法的修饰符?

2024-04-26 17:39:38 发布

您现在位置:Python中文网/ 问答频道 /正文

在下面的代码中,我为类Class方法创建了一个装饰器。我注意到,即使没有创建类实例,也会调用这个decorator! 而不是在类中调用这些方法!你知道吗

有什么解释吗?你知道吗

装饰师:

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 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

Tags: and方法nameselfreturnisdeffunction
3条回答

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

@somedecorator
def foo():
    pass

严格等同于

def foo():
    pass

foo = somedecorator(foo)

在您的例子中,您明确地调用了decorator函数:

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

相当于:

def f1(self):
    pass

 _effective_decorator = deco(class_deco)

 f1 = _effective_decorator(f1)

这就是为什么在导入时执行inner_function。你知道吗

接受额外参数的decorator需要更高级别的嵌套,因此从技术上讲,您的decorator应该如下所示:

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

但是如果关键是获取方法真正属于的类的名称,这仍然是错误的-您应该从调用该方法的实例获取类,不要试图在decorator调用中硬编码它(这永远不会像预期的那样工作,因为当您将decorator应用到函数时,真正的类不存在)。所以正确的实现应该是这样的:

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

注意:这当然不会处理classmethods和staticmethods。你知道吗

下面是一个演示,展示了构建装饰器的两种可能方法:


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)

装饰剂只是以下方面的合成糖

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

与-

f1 = deco(class_deco)(f1)

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

相关问题 更多 >