在Python的弱引用机制中,weakref.proxy可以创建对象的弱引用代理,代理对象的行为和原对象基本一致,但不会增加原对象的引用计数。默认情况下,weakref.proxy会将大部分操作直接转发给原对象,但如果我们想要在代理过程中添加自定义逻辑,比如拦截属性访问、修改返回值或者添加权限校验,就需要对代理行为进行调整。
weakref.proxy的基本使用
首先我们先回顾一下weakref.proxy的默认行为,它返回的是一个代理对象,该对象会将对它的操作转发到被代理的原对象上,当原对象被销毁后,访问代理对象会抛出ReferenceError。
下面是一个简单的默认使用示例:
import weakref
class MyClass:
def __init__(self, value):
self.value = value
def show(self):
return f"当前值: {self.value}"
# 创建原对象
obj = MyClass(10)
# 创建弱引用代理
proxy = weakref.proxy(obj)
# 访问代理的属性,会转发到原对象
print(proxy.value) # 输出: 10
print(proxy.show()) # 输出: 当前值: 10
# 删除原对象
del obj
# 此时访问代理会报错
try:
print(proxy.value)
except ReferenceError as e:
print(f"捕获到错误: {e}") # 输出: 捕获到错误: weakly-referenced object no longer exists
自定义代理行为的核心思路
weakref.proxy的代理行为依赖于原对象的特殊方法,如果我们想要自定义代理行为,不能直接修改weakref.proxy本身的实现,而是可以通过在原对象中定义相关的特殊方法,来控制代理转发操作时的逻辑。其中最常用的特殊方法是__getattr__和__setattr__,这两个方法会在代理访问或修改属性时被触发。
需要注意的是,weakref.proxy在转发属性访问时,会先尝试直接访问原对象的属性,如果失败才会触发__getattr__,因此我们可以在__getattr__中添加自定义逻辑,比如记录访问日志、校验权限或者返回默认值。
实现自定义代理行为的完整示例
下面的示例我们实现一个自定义需求:当通过weakref.proxy访问原对象的属性时,如果是数值类型的属性,就将其值乘以2再返回;如果是方法调用,就记录调用日志后再执行原方法。
import weakref
import time
class CustomObj:
def __init__(self, num, name):
self.num = num
self.name = name
self._access_log = []
def __getattr__(self, item):
# 自定义属性访问逻辑
# 先检查是否是原对象已有的属性
try:
val = object.__getattribute__(self, item)
except AttributeError:
# 如果不存在该属性,抛出常规错误
raise AttributeError(f"'CustomObj' object has no attribute '{item}'")
# 如果是数值类型的属性,乘以2返回
if isinstance(val, (int, float)):
return val * 2
# 如果是方法,包装后返回,添加日志逻辑
if callable(val):
def wrapper(*args, **kwargs):
log_time = time.strftime("%Y-%m-%d %H:%M:%S")
self._access_log.append(f"{log_time} 调用了方法 {item}")
return val(*args, **kwargs)
return wrapper
# 其他类型直接返回
return val
def get_log(self):
return self._access_log
def add(self, x):
return self.num + x
# 创建原对象
obj = CustomObj(5, "测试对象")
# 创建弱引用代理
proxy = weakref.proxy(obj)
# 访问数值属性,会被自定义逻辑处理
print(f"代理访问num属性: {proxy.num}") # 输出: 代理访问num属性: 10(原5*2)
# 访问非数值属性,正常返回
print(f"代理访问name属性: {proxy.name}") # 输出: 代理访问name属性: 测试对象
# 调用方法,会触发日志逻辑
result = proxy.add(3)
print(f"调用add方法结果: {result}") # 输出: 调用add方法结果: 8(原5+3)
# 查看访问日志
print(f"访问日志: {obj.get_log()}") # 输出包含调用add方法的日志记录
# 删除原对象后,代理访问报错
del obj
try:
print(proxy.num)
except ReferenceError as e:
print(f"代理访问失败: {e}")
注意事项
- 自定义
__getattr__时,要避免无限递归,比如不要直接写self.item,而是使用object.__getattribute__来获取原属性。 - weakref.proxy只能代理支持弱引用的对象,比如自定义类的实例默认是支持弱引用的,但如果类定义了
__slots__且没有添加__weakref__槽位,就无法创建弱引用代理。 - 自定义的代理逻辑不要修改原对象的核心生命周期,否则可能导致弱引用机制失效。
如果需要更复杂的代理行为,比如拦截所有操作而不仅仅是属性访问,也可以考虑自定义一个代理类,在代理类内部持有原对象的弱引用,然后重写代理类的相关特殊方法,不过这种方式相比直接使用weakref.proxy会更复杂,需要根据实际需求选择。
weakref_proxy自定义代理行为弱引用Python对象__getattr__修改时间:2026-06-28 12:21:56