gpt4 book ai didi

python - 拦截python类中的魔术方法调用

转载 作者:行者123 更新时间:2023-12-01 12:02:26 25 4
gpt4 key购买 nike

我正在尝试创建一个类来包装将在多个其他对象中使用的值。出于计算原因,目的是让这个包装值只计算一次,并将对该值的引用传递给它的用户。由于其对象容器模型,我认为这在 vanilla python 中是不可能的。相反,我的方法是传递一个包装类,定义如下:

class DynamicProperty():

def __init__(self, value = None):
# Value of the property
self.value: Any = value

def __repr__(self):
# Use value's repr instead
return repr(self.value)

def __getattr__(self, attr):
# Doesn't exist in wrapper, get it from the value
# instead
return getattr(self.value, attr)

以下按预期工作:

wrappedString = DynamicProperty("foo")
wrappedString.upper() # 'FOO'

wrappedFloat = DynamicProperty(1.5)
wrappedFloat.__add__(2) # 3.5

但是,通过正常语法隐式调用 __add__ 会失败:

wrappedFloat + 2  # TypeError: unsupported operand type(s) for 
# +: 'DynamicProperty' and 'float'

有没有一种方法可以拦截这些隐式方法调用,而无需为 DynamicProperty 显式定义魔术方法以调用其 value 属性上的方法?

最佳答案

谈论“通过引用传递”只会让您感到困惑。将该术语保留在您可以选择的语言中,以及它会产生影响的地方。在 Python 中,你总是传递 objects - 这种传递相当于“通过引用传递” - 对于 all 对象 - 从 None 到 int 再到实时异步网络连接池实例。

除此之外:语言遵循的从对象检索属性的算法很复杂,有详细信息 - 实现 __getattr__ 只是冰山一角。完整阅读名为“Data Model”的文档将使您更好地掌握检索属性所涉及的所有机制。

就是说,这里是“魔术”或“双下划线”方法的工作原理 -(名称前后两个下划线的特殊函数):当您使用需要存在实现它的方法的运算符时(如 __add__ 用于 +),该语言检查对象的 class 是否有 __add__ 方法 - 而不是实例。类上的 __getattr__ 只能为该类的实例动态创建属性。但这不是唯一的问题:您可以创建一个元类(继承自 type)并在该元类上放置一个 __getattr__ 方法。对于您从 Python 执行的所有查询,看起来您的对象在其类中具有 __add__(或任何其他 dunder 方法)。但是,对于 dunder 方法,Python 不会通过正常的属性查找机制 - 如果 dunder 方法“物理上”在那里,它会直接“查找”类。内存结构中有插槽,用于保存每个可能的 dunder 方法的类 - 它们要么引用相应的方法,要么是“空”(在 Python 端用 C 编码时这是“可见的”,默认情况下dir 将在这些方法存在时显示它们,如果不存在则忽略它们)。如果它们不存在,Python 只会“说”该对象没有实现该操作和句点。

使用您想要的代理对象解决此问题的方法是创建一个代理类,该代理类具有您要包装的类中的 dunder 方法,或者具有所有可能的方法,并在被调用时检查是否底层对象实际上实现了调用的方法。

这就是为什么“严肃”的代码很少(如果有的话)提供真正的“透明”代理对象。有异常(exception),但是从“Weakrefs”到“super()”再到 concurrent.futures,仅举几个核心语言和 stdlib 中的例子,没有人尝试“完全工作的透明代理”——相反,api 是更像是您在包装器上调用“.value()”或“.result()”方法来获取原始对象本身。

但是,正如我上面所述,它可以完成。我什至在 pypi 上有一个小的(长期未维护的)包可以做到这一点,为 future 包装一个代理。代码位于 https://bitbucket.org/jsbueno/lelo/src/master/lelo/_lelo.py

关于python - 拦截python类中的魔术方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60620112/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com