python - 使用 __setattr__ 和 __getattr__ 与 __slots__ 进行委托而不触发无限递归
问题描述
class A:
__slots__ = ("a",)
def __init__(self) -> None:
self.a = 1
class B1:
__slots__ = ("b",)
def __init__(self, b) -> None:
self.b = b
def __getattr__(self, k):
return getattr(self.b, k)
def __setattr__(self, k, v):
setattr(self.b, k, v)
class B2:
__slots__ = ("b",)
def __init__(self, b) -> None:
self.b = b
def __getattr__(self, k):
return getattr(super().__getattr__("b"), k)
def __setattr__(self, k, v):
setattr(super().__getattr__("b"), k, v)
class B3:
__slots__ = ("b",)
def __init__(self, b) -> None:
self.b = b
def __getattr__(self, k):
return getattr(getattr(super(), "b"), k)
def __setattr__(self, k, v):
setattr(getattr(super(), "b"), k, v)
a = A()
b = B1(a)
print(b.a) # RecursionError: maximum recursion depth exceeded
b = B2(a)
print(b.a) # AttributeError: 'super' object has no attribute '__getattr__'
b = B3(a)
print(b.a) # AttributeError: 'super' object has no attribute 'b'
解决方案
更合适的方法是在委托之前检查属性名称是否在__slots__
类层次结构中的任何可用中:
class BCorrect(object):
__slots__ = ('b',)
def __init__(self, b) -> None:
self.b = b
def _in_slots(self, attr) -> bool:
for cls in type(self).__mro__:
if attr in getattr(cls, '__slots__', []):
return True
return False
def __getattr__(self, attr):
if self._in_slots(attr):
return object.__getattr__(self, attr)
return getattr(self.b, attr)
def __setattr__(self, attr, value):
if self._in_slots(attr):
object.__setattr__(self, attr, value)
return
setattr(self.b, attr, value)
这样做的好处是不会破坏继承,也不需要在__init__
.
推荐阅读
- redis - 如何在 Redis 流中使用背压?
- python - BeautifulSoup 通配符搜索?
- marklogic - 精确匹配失败时自定义 noextract 匹配的 Marklogic Smart Mastering 选项
- c# - 如何将一些对象添加/附加到对象数组中
- ios - 如何在 Xcode 中的函数之间暂停?
- amazon-web-services - AWS Elemental MediaConvert 流段文件安全性
- bash - 如何在 bash 脚本中使用 awk 和一起阅读?
- python - 在python中绘制带有图例的垂直线
- c++ - 什么时候应该使用模板化参数和构造参数?
- c++ - 有关 TLS 连接和证书的信息