如何让类的所有方法(含继承方法)被调用时执行指定逻辑?
实现子类所有方法调用时自动执行指定逻辑
我需要实现这样的逻辑:当一个子类(实际场景是list的子类)的**所有方法(包括从父类继承的方法)**被调用时,自动执行一段指定的代码。
示例需求代码如下:
class Foo(another_class): def __init__(self, bar): self.bar = bar super().__init__(self.bar) def function_to_be_called(self): self.bar += 1 def function(self): # 执行一些操作 pass foo = Foo(0) foo.function() foo.inherited_function() print(foo.bar) # 期望输出2,因为function和inherited_function各被调用一次
我尝试过重写__getattribute__魔术方法,但要么触发无限递归,要么出现异常行为。
第一次尝试:触发RecursionError
class Foo(another_class): def __init__(self, bar): self.bar = bar super().__init__(self.bar) def function_to_be_called(self): self.bar += 1 def function(self): # 执行一些操作 pass def __getattribute__(self, attr): method = another_class.__getattribute__(self, attr) self.function_to_be_called() # 调用这个方法需要通过__getattribute__查找,导致无限循环 # 就算把self.function_to_be_called()换成直接的self.bar +=1,也会因为查找bar触发__getattribute__,同样无限递归 return method
第二次尝试:出现异常行为(以list子类场景为例)
# 假设another_class有append方法 class Foo(another_class): def __init__(self, bar): self.bar = bar super().__init__(self.bar) def function(self): print(self.bar) def __getattribute__(self, attr): method = another_class.__getattribute__(self, attr) if callable(method): self.bar.sort() # 对bar执行排序操作 return method foo = Foo([3, 1, 2]) print(foo) # 实际输出[3, 1, 2],但期望是[1, 2, 3],没有执行排序 foo.append(1) print(foo) # 实际输出[3, 1, 2, 1],期望是[1, 1, 2, 3],还是没排序 foo.function() # 输出[1, 2, 3],之前append的1消失了(后续测试在实际场景中又正常了,原因不明)
正确实现方案
要避免无限递归和异常行为,核心是在__getattribute__内部获取属性时,绕过当前类的__getattribute__,直接调用基类object的对应方法,同时排除不需要触发逻辑的特殊属性,避免递归。
针对计数需求的实现
class Foo(list): # 实际场景为list的子类 def __init__(self, bar): self.bar = bar super().__init__(self.bar) def function_to_be_called(self): # 用object.__getattribute__直接获取bar,避免触发当前__getattribute__ current_bar = object.__getattribute__(self, 'bar') object.__setattr__(self, 'bar', current_bar + 1) def function(self): # 自定义方法 pass def __getattribute__(self, attr): # 直接从object获取属性,绕过当前类的__getattribute__ attr_value = object.__getattribute__(self, attr) # 排除function_to_be_called本身,避免递归调用 if attr == 'function_to_be_called': return attr_value # 判断是否为可调用方法,包装后返回 if callable(attr_value): def wrapper(*args, **kwargs): self.function_to_be_called() return attr_value(*args, **kwargs) return wrapper else: return attr_value # 测试 foo = Foo(0) foo.append(1) # 继承自list的方法,触发计数逻辑 foo.function() # 自定义方法,触发计数逻辑 print(foo.bar) # 输出2,符合预期
针对排序需求的实现
class Foo(list): def __init__(self, bar): self.bar = bar.copy() # 避免和list自身数据混淆 super().__init__(bar) def __getattribute__(self, attr): attr_value = object.__getattribute__(self, attr) # 排除bar属性本身,避免获取bar时触发排序导致递归 if attr == 'bar': return attr_value if callable(attr_value): def wrapper(*args, **kwargs): # 先执行原方法,再执行排序逻辑 result = attr_value(*args, **kwargs) bar = object.__getattribute__(self, 'bar') bar.sort() return result return wrapper else: return attr_value # 测试 foo = Foo([3, 1, 2]) foo.append(1) print(foo.bar) # 输出[1, 1, 2, 3],符合预期 foo.function() # 输出排序后的bar
内容的提问来源于stack exchange,提问作者cd-CreepArghhh
相关产品推荐
相关产品推荐

