如何在Python中自动将未实现的方法委托给其他类?
问题:如何在抽象基类中自动将未实现的方法转发给其他类实例
我有一个实现了x()和y()的类A,还有一个实现了z()的类B。现在有一个基类AbstractA,需要检测A上所有未实现的方法调用(比如z())并转发给B的实例。注意因为框架限制,A不能继承自B。示例代码如下:
from abc import ABC, abstractmethod class AbstractA(ABC): # 需要在这里实现捕获未实现方法并转发给B的逻辑,可访问B的实例(比如context.b) @abstractmethod def x(): pass @abstractmethod def y(): pass class A(AbstractA): def __init__(self): super().__init__() def x(): print('running x()') def y(): print('running y()') class B: def __init__(some plumbing args): super().__init__(some plumbing args) def z(): print('running z()') a = A() a.x() a.y() a.z()
需求背景
这个场景来自分层架构:数据访问层(DAL)是一组DAO类,封装所有数据库操作;服务应用层(SAL)基于DAL构建,整合数据与业务逻辑。比如PersonService调用PersonDao实现业务API,但客户端有时会请求直接调用DAO中的方法(比如find_by_id),希望在服务类的抽象基类层面自动完成方法透传,不用为每个DAO方法写重复的转发代码,让服务类成为DAO的外观层。
解决方案
核心是利用Python的__getattr__魔法方法——它会在访问对象不存在的属性(包括方法)时被触发。我们可以在AbstractA中实现这个方法,将未找到的方法转发给B的实例。
实现步骤
- 让
AbstractA持有B的实例引用:可以通过全局上下文获取,或者在初始化时传入(推荐后者,更灵活)。 - 实现
__getattr__方法:当调用A中未实现的方法时,从B的实例中获取对应方法并返回。
完整代码示例(基于上下文获取B实例)
from abc import ABC, abstractmethod # 模拟上下文,提供B的实例 class Context: def __init__(self): self.b = B() context = Context() class AbstractA(ABC): def __getattr__(self, name): # 捕获未实现的方法,转发给B的实例 return getattr(context.b, name) @abstractmethod def x(self): pass @abstractmethod def y(self): pass class A(AbstractA): def x(self): print('running x()') def y(self): print('running y()') class B: def __init__(self): pass def z(self): print('running z()') # 测试 a = A() a.x() # 输出: running x() a.y() # 输出: running y() a.z() # 输出: running z()
更灵活的实现(初始化时传入B实例)
如果不想依赖全局上下文,可以通过初始化参数传递B实例:
from abc import ABC, abstractmethod class AbstractA(ABC): def __init__(self, b_instance): self.b = b_instance def __getattr__(self, name): return getattr(self.b, name) @abstractmethod def x(self): pass @abstractmethod def y(self): pass class A(AbstractA): def __init__(self, b_instance): super().__init__(b_instance) def x(self): print('running x()') def y(self): print('running y()') class B: def __init__(self): pass def z(self): print('running z()') # 测试 b = B() a = A(b) a.x() a.y() a.z()
注意事项
__getattr__只会在访问不存在的属性时触发,如果A中已经实现了某个方法(比如x()),不会被转发,符合需求。- 确保
B实例在AbstractA中可正常访问,避免出现属性不存在的错误。
内容的提问来源于stack exchange,提问作者SkyWalker
相关产品推荐
相关产品推荐

