我在将动态添加的方法添加到Python类时遇到问题。考虑下面的类集,其中为任何已定义的<some>_str方法动态添加的方法<some>。class ToStr(object): @classmethod def add_str_method(cls, name): method = getattr(cls, name) def str_method(self, *args, **kwargs): return str(method(*args, **kwargs)) setattr(cls, '{0}_str'.format(name), str_method)class Even(ToStr): @classmethod def even(cls, values): return [value for value in values if value%2 == 0]Even.add_str_method('even')class Large(ToStr): @classmethod def large(cls, values): filtered = [value for value in values if value > 5] if hasattr(cls, 'even'): filtered = cls.even(filtered) return filteredLarge.add_str_method('large')class Special(Even, Large): pass请注意,动态添加的%_str函数是实例方法,而%是类方法。同样,large方法取决于even方法的存在,该方法由hasattr(cls, 'even')确定。现在,我在每个类中比较%和%_str方法的输出,结果令我感到困惑:# Even.evenEven().even(values) [0, 2, 4, 6, 8, 10]Even().even_str(values) [0, 2, 4, 6, 8, 10]# Large.largeLarge().large(values) [6, 7, 8, 9, 10]Large().large_str(values) [6, 7, 8, 9, 10]# Special.evenSpecial().even(values) [0, 2, 4, 6, 8, 10]Special().even_str(values) [0, 2, 4, 6, 8, 10]# Special.largeSpecial().large(values) [6, 8, 10]Special().large_str(values) [6, 7, 8, 9, 10]尽管Special.large_str()类应从Special类继承并通过Even检查,但hasattr方法不会删除偶数。所以我的问题是:为什么在动态添加方法时为什么hasattr不能识别这些方法?更新:此效果不依赖于Special类定义中超类的顺序。如果将even和large方法定义为实例方法而不是类方法(如下面的示例),则不会发生这种效果。class ToStr(object): @classmethod def add_str_method(cls, name): method = getattr(cls, name) def str_method(self, *args, **kwargs): return str(method(self, *args, **kwargs)) setattr(cls, '{0}_str'.format(name), str_method)class Even(ToStr): def even(self, values): return [value for value in values if value%2 == 0]Even.add_str_method('even')class Large(ToStr): def large(self, values): filtered = [value for value in values if value > 5] if hasattr(self, 'even'): filtered = self.even(filtered) return filteredLarge.add_str_method('large') 最佳答案 这种情况下的问题是,可以在类上调用classmethod,因此当您在类上对getattr进行classmethod时,它将是一个绑定方法(第一个参数已被填充)。这意味着您将添加记住在getattr中使用的类的方法。因此,对Special().large_str(values)的调用将调用str_method,但是内部的method调用仅使用Large.large调用cls=Large,但是Large本身没有even方法。另一方面,not- classmethods将在getattr中返回一个自由函数,因此第一个参数将不固定,这就是为什么您需要在self调用中的method参数中包含在第二种方法中。class ToStr(object): @classmethod def add_str_method(cls, name): method = getattr(cls, name) def str_method(self, *args, **kwargs): print(method) # added a print! return str(method(*args, **kwargs)) setattr(cls, '{0}_str'.format(name), str_method)class Even(ToStr): @classmethod def even(cls, values): return [value for value in values if value%2 == 0]Even.add_str_method('even')class Large(ToStr): @classmethod def large(cls, values): print(cls) # added a print! filtered = [value for value in values if value > 5] if hasattr(cls, 'even'): filtered = cls.even(filtered) return filteredLarge.add_str_method('large')class Special(Even, Large): pass说明了这种行为:>>> Special().large_str(list(range(11)))<bound method Large.large of <class '__main__.Large'>> # bound method<class '__main__.Large'> # wrong cls'[6, 7, 8, 9, 10]' # wrong result普通方法变体会打印:<function Large.large at 0x0000024B2FE808C8> # free function<__main__.Special object at 0x0000024B2FE7C3C8> # correct instance'[6, 8, 10]' # correct result在这种情况下,可能的解决方案/解决方法是在str_method中调用包装的函数(在这种情况下,该函数将返回未绑定的方法):class ToStr(object): @classmethod def add_str_method(cls, name): method = getattr(cls, name) def str_method(self, *args, **kwargs): return str(method.__func__(self, *args, **kwargs)) # this line changed setattr(cls, '{0}_str'.format(name), str_method)关于python - 动态添加的方法在子类中对hasattr()不可见,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43683218/
10-10 14:58