<p>谈论“参考传递”只会让你感到困惑。将这些术语保留在您可以选择的语言中,并保留在不同的语言中。在Python中,您总是将<em>对象</em>四处传递,这种传递相当于“按引用传递”<em>所有</em>对象,从None传递到int,再传递到活动的异步网络连接池实例</p>
<p>这样一来:语言从对象中检索属性所遵循的算法是复杂的,有细节-实现<code>__getattr__</code>只是冰山一角。完整阅读名为“<a href="https://docs.python.org/3/reference/datamodel.html" rel="nofollow noreferrer">Data Model</a>”的文档将使您更好地掌握检索属性所涉及的所有机制</p>
<p>这就是说,下面是它对“magic”或“dunder”方法的工作方式-(在名称前有两个下划线,在名称后有两个下划线的特殊函数):当您使用要求存在实现它的方法的运算符时(如<code>__add__</code>for <code>+</code>),该语言会检查对象的<em>类</em>for <code>__add__</code>方法-而不是实例。类上的<code>__getattr__</code>可以仅为该类的实例动态创建属性。
但这不是唯一的问题:您可以创建一个元类(从<code>type</code>继承)并在这个元类上放置<code>__getattr__</code>方法。对于从Python执行的所有查询,对象的类中似乎有<code>__add__</code>(或任何其他dunder方法)。但是,对于dunder方法,Python不通过正常的属性查找机制——如果dunder方法“物理地”在类中,它会直接“查看”该类。内存结构中有一些槽保存每个可能的dunder方法的类,它们要么引用相应的方法,要么为“null”(在Python端用C编写代码时,这是“可见的”,默认的<code>dir</code>将在这些方法存在时显示它们,如果没有,则忽略它们)。如果它们不存在,Python只会“说”对象没有实现该操作和周期</p>
<p>使用您想要的代理对象解决这个问题的方法是创建一个代理类,该类要么以您想要包装的类中的dunder方法为特征,要么以所有可能的方法为特征,在被调用时,检查底层对象是否实际实现了被调用的方法</p>
<p>这就是为什么“严肃”代码很少(如果有的话)提供真正的“透明”代理对象的原因。也有例外,但从“Weakrefs”、到“super()”、再到concurrent.futures,在核心语言和stdlib中仅举几例,没有人尝试“完全工作的透明代理”——相反,api更像是在包装器上调用“.value()”或“.result()”方法来访问原始对象本身</p>
<p>然而,正如我上面所描述的,它可以<em>完成。我甚至在pypi上有一个小的(长而未维护的)包,可以实现这一点,为未来包装一个代理。
代码位于<a href="https://bitbucket.org/jsbueno/lelo/src/master/lelo/_lelo.py" rel="nofollow noreferrer">https://bitbucket.org/jsbueno/lelo/src/master/lelo/_lelo.py</a></p>