透明代理(已弃用)¶
警告
这是一个很久以前尝试过的实验性功能,我们没有找到真正好的用例。基本功能仍然存在,但我们不建议使用它。以下示例中的一些可能不再有效(例如,您不能再对列表对象进行 tproxy)。其余部分可以通过在标准 Python 中进行黑客攻击来完成。如果有人有兴趣再次研究 tproxy,欢迎他们,但我们不认为这是一个有趣的扩展。
PyPy 的透明代理允许将对象上的操作路由到可调用对象。应用程序级代码可以自定义对象而不干扰类型系统 - type(proxied_list) is list
在 proxied_list
是代理的内置 list
时保持为真 - 同时让你完全控制对 proxied_list
执行的所有操作。
有关透明代理的更多背景、动机和用法,请参见 [D12.1]。
核心机制示例¶
以下示例代理了一个列表,并在任何加法操作上返回 42
$ py.py --objspace-std-withtproxy
>>>> from __pypy__ import tproxy
>>>> def f(operation, *args, **kwargs):
>>>> if operation == '__add__':
>>>> return 42
>>>> raise AttributeError
>>>>
>>>> i = tproxy(list, f)
>>>> type(i)
list
>>>> i + 3
42
记录内置对象上所有操作的示例¶
假设我们想要一个列表,它存储对它执行的所有操作以供以后分析。我们可以使用 lib_pypy/tputil.py 模块来帮助透明地代理内置实例
from tputil import make_proxy
history = []
def recorder(operation):
history.append(operation)
return operation.delegate()
>>>> l = make_proxy(recorder, obj=[])
>>>> type(l)
list
>>>> l.append(3)
>>>> len(l)
1
>>>> len(history)
2
make_proxy(recorder, obj=[])
创建一个透明列表代理,它允许我们将操作委托给 recorder()
函数。调用 type(l)
根本不会导致任何操作执行。
请注意,append()
显示为 __getattribute__()
,而 type(l)
根本没有显示 - 类型是代理控制器无法更改的实例的唯一方面。
透明代理 PyPy 内置对象和支持¶
如果您正在使用 –objspace-std-withtproxy 选项,则 __pypy__ 模块提供以下内置函数
-
tproxy
(type, controller) 返回一个代理对象,该对象表示给定的类型,并将所有对该类型的操作转发到控制器。在每次操作时,都会调用
controller(opname, *args, **kwargs)
。
-
get_tproxy_controller
(obj)¶ 返回给定对象的负责控制器。对于非代理对象,将返回
None
。
tputil 辅助模块¶
该 lib_pypy/tputil.py 模块提供
-
make_proxy
(controller, type, obj)¶ 创建一个由给定
controller
可调用对象控制的透明代理。该代理将显示为给定类型的完全常规实例,但对其的所有操作都将发送到指定的控制器 - 控制器在每次操作时都会收到一个ProxyOperation
实例。如果type
未指定,则默认为type(obj)
(如果指定了obj
)。ProxyOperation 实例具有以下属性
-
proxyobj
¶ 此操作的透明代理对象。
-
opname
¶ 此操作的名称。
-
args
¶ 此操作的任何位置参数。
-
kwargs
¶ 此操作的任何关键字参数。
-
obj
¶ (仅当提供给
make_proxy()
时)一个具体对象。
-
delegate
()¶ 如果在调用
make_proxy()
时指定了具体对象实例obj
,则可以调用proxyoperation.delegate()
将操作委托给对象实例。
-
其他要点¶
可以使用透明代理执行许多任务,包括但不限于
- 对象的远程版本,我们可以在其上直接执行操作(想想透明分布)。
- 访问持久性存储,例如数据库(想象一个看起来像任何其他对象的 SQL 对象映射器)。
- 访问外部数据结构,例如其他语言,作为普通对象(当然,某些操作可能会引发异常,但由于操作是在应用程序级别执行的,因此这不是主要问题)。
实现说明¶
PyPy 的标准对象空间允许我们在内部拥有类型的多个实现,并在运行时更改实现,而应用程序级代码始终看到完全相同的类型和对象。已经实现了使用这些功能的多个性能优化:替代对象实现。透明代理使用此架构将控制权返回到应用程序级代码。
透明代理是在 标准对象空间 之上实现的,位于 pypy/objspace/std/proxyobject.py、pypy/objspace/std/proxyobject.py 和 pypy/objspace/std/transparent.py 中。要使用它们,您需要将 –objspace-std-withtproxy 选项传递给 pypy
或 translate.py
。这将注册名为 W_TransparentXxx
的实现 - 通常对应于适当的 W_XxxObject
- 并且包括一些解释器技巧,用于那些过于接近解释器而无法在标准对象空间中实现的对象。可以通过这种方式代理的对象类型包括用户创建的类和函数、列表、字典、异常、回溯和帧。
[D12.1] | 高级后端和解释器特性原型,PyPy EU 报告,2007 年,https://foss.heptapod.net/pypy/extradoc/-/tree/branch/extradoc/eu-report/D12.1_H-L-Backends_and_Feature_Prototypes-2007-03-22.pdf |