
本文介绍如何让自定义类自动将所有未定义方法调用转发至其内部封装的对象,从而实现零样板代码的代理行为,适用于封装第三方对象或动态类型实例的场景。
本文介绍如何让自定义类自动将所有未定义方法调用转发至其内部封装的对象,从而实现零样板代码的代理行为,适用于封装第三方对象或动态类型实例的场景。
在 Python 面向对象设计中,有时我们需要对某个外部对象(如字符串、列表、requests.Response、自定义类实例等)进行轻量级包装,既不继承(因构造逻辑未知或不可控),又希望用户能像直接操作原对象一样调用其所有方法和属性。此时,手动重写每个方法显然不可行——尤其当被包装对象拥有数十甚至上百个接口时。
Python 提供了数据模型钩子 __getattr__,它仅在常规属性查找失败(即实例字典、类及其 MRO 中均未找到该属性)时被调用。这使其成为实现透明代理(Transparent Proxy) 的理想机制:我们将所有“找不到”的属性访问,统一委托给内部持有的 self.ele 对象处理。
以下是标准实现:
class A:
def __init__(self, ele):
self.ele = ele
def __getattr__(self, name):
return getattr(self.ele, name)✅ 效果示例:
立即学习“Python免费学习笔记(深入)”;
# 包装一个字符串
a = A("hello world")
print(a.split()) # → ['hello', 'world']
print(a.upper()) # → 'HELLO WORLD'
print(a.__len__()) # → 11(注意:__len__ 是特殊方法,但 __getattr__ 仍可捕获)
print(a.count('l')) # → 3⚠️ 关键注意事项:
- __getattr__ 仅对缺失属性触发,不会覆盖已定义的属性或方法。例如,若你在 A 中定义了 def __str__(self): return "A()",则 str(A(...)) 将使用你定义的版本,而非 self.ele.__str__()。
- 特殊方法(如 __len__, __iter__, __call__)通常不会通过 __getattr__ 触发 —— Python 在多数内置操作中会直接查找 type(obj).__special__,跳过实例级 __getattr__。若需代理特殊方法,需显式实现(如 def __len__(self): return len(self.ele))或结合 __getattribute__(慎用,易引发递归)。
- 若 self.ele 本身也不含该属性,getattr(self.ele, name) 将抛出 AttributeError,该异常会被正常传播,符合预期行为。
- 此模式不改变原对象生命周期,A 实例仅持有一个引用,无额外内存开销。
? 进阶提示:
如需记录代理调用、添加权限校验或做参数预处理,可在 __getattr__ 内部增强逻辑:
def __getattr__(self, name):
attr = getattr(self.ele, name)
if callable(attr):
def wrapped(*args, **kwargs):
print(f"[Proxy] Calling {name} on {type(self.ele).__name__}")
return attr(*args, **kwargs)
return wrapped
return attr综上,__getattr__ 是构建灵活、低侵入性代理类的核心工具。它让封装变得简洁而强大,是 Python 动态特性的典型实践。


















