Python类方法地址差异、元素类型及代码行为咨询
类方法引用匹配问题解析
先贴出问题中的代码:
class Parent: @classmethod def func1(cls): print("hello func1") @classmethod def func2(cls): print("hello func2") @classmethod def func3(cls): print("hello func3") CALCULATE = [func1, func2, func3] NO_CALCULATE = [] @classmethod def calculate_kpis(cls): for func in cls.CALCULATE: if func not in cls.NO_CALCULATE: func.__get__(cls)() class Child(Parent): NO_CALCULATE = [Parent.func1] #REMOVE THIS CALCULATION FROM CHILD if __name__ == "__main__": p1 = Child() p1.calculate_kpis()
现象(a):NO_CALCULATE中的func1与Parent类的func1地址不同
当通过Parent.func1访问类方法时,Python会返回一个绑定的类方法对象——这是类方法装饰器生成的包装器,每次访问这个属性,都会生成一个新的绑定实例,内存地址自然不同。而Parent类中CALCULATE列表里的func1,是未绑定的类方法对象(定义时直接引用装饰器返回的原始对象),两者是不同的实例,地址必然不一样。
现象(b):CALCULATE与NO_CALCULATE元素类型不同
CALCULATE里的func1/func2/func3:是@classmethod装饰器返回的classmethod类实例,属于未绑定的类方法对象,还没和具体类绑定。NO_CALCULATE里的Parent.func1:通过类属性访问类方法时,Python自动调用classmethod对象的__get__方法,返回的是绑定到Parent类的method对象,和前者不是同一种类型。
整体代码行为
因为CALCULATE的元素是classmethod实例,NO_CALCULATE的元素是绑定后的method实例,两者类型和实例都不匹配,所以func not in cls.NO_CALCULATE的判断永远为True,最终三个函数都会被执行。
修正思路(可选)
如果要实现排除指定类方法的逻辑,可以存储方法的名称字符串替代方法对象,示例如下:
class Parent: @classmethod def func1(cls): print("hello func1") @classmethod def func2(cls): print("hello func2") @classmethod def func3(cls): print("hello func3") CALCULATE = [func1, func2, func3] NO_CALCULATE = [] @classmethod def calculate_kpis(cls): exclude_names = {func.__name__ for func in cls.NO_CALCULATE} for func in cls.CALCULATE: if func.__name__ not in exclude_names: func.__get__(cls)() class Child(Parent): NO_CALCULATE = [Parent.func1]
内容的提问来源于stack exchange,提问作者nickli
相关产品推荐
相关产品推荐

