通用代理和包装器类型

ProxyTypes的Python项目详细描述


peak.util.proxies模块为创建 普通Python对象的代理和包装器。自动代理对象 将所有属性访问和操作委托给代理对象。包装纸 是相似的,但是可以子类化以允许附加属性和 要添加到包装对象的操作。

注意,这些代理类型不是有意篡改的; 可以使用代理的^{tt2}轻松访问对象的形式$ 属性,有些代理类型甚至允许设置此属性。(这个可以 对于那些懒散地创建循环结构并因此需要 能够发布“正向引用”代理。

Proxy Basics

下面是ObjectProxy类型的快速演示:

>>> from peak.util.proxies import ObjectProxy
>>> p = ObjectProxy(42)

>>> p
42

>>> isinstance(p, int)
True

>>> p.__class__
<... 'int'>

>>> p*2
84

>>> 'X' * p
'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

>>> hex(p)
'0x2a'

>>> chr(p)
'*'

>>> p ^ 1
43

>>> p ** 2
1764

如您所见,代理实际上与它的对象没有区别 代理,除了通过其^ {tt2} $属性,及其^ tT5}$:

>>> p.__subject__
42

>>> type(p)
<class 'peak.util.proxies.ObjectProxy'>

您可以更改ObjectProxy__subject__,然后它将 参考其他内容:

>>> p.__subject__ = 99
>>> p
99
>>> p-33
66

>>> p.__subject__ = "foo"
>>> p
'foo'

所有操作都委派给主题,包括setattr和delattr:

>>> class Dummy: pass
>>> d = Dummy()
>>> p = ObjectProxy(d)

>>> p.foo = "bar"
>>> d.foo
'bar'

>>> del p.foo
>>> hasattr(d,'foo')
False

Callback Proxies

有时,您可能希望在任何时候动态地确定代理的主题 使用代理。为此,可以使用CallbackProxy类型, 它接受回调函数并创建将调用 回调以获取目标。下面是一个计数器的快速示例 每次使用都会递增,从零到三:

>>> from peak.util.proxies import CallbackProxy

>>> ct = -1
>>> def callback():
...     global ct
...     if ct == 3: raise StopIteration
...     ct += 1
...     return ct

>>> counter = CallbackProxy(callback)

>>> counter
0
>>> counter
1
>>> str(counter)
'2'
>>> hex(counter)
'0x3'

>>> counter
Traceback (most recent call last):
  ...
StopIteration

如您所见,在尝试使用 代理。这是一个有点傻的例子;一个更好的例子是 始终等于其线程id的thread_id代理 跑进去。

回调代理的回调可以通过^{tt10}获取或更改$ 以及set_callback函数:

>>> from peak.util.proxies import get_callback, set_callback
>>> set_callback(counter, lambda: 42)

>>> counter
42

>>> get_callback(counter)
<function <lambda> at ...>

Lazy Proxies

LazyProxy类似于CallbackProxy,但它的回调被调用 最多一次,然后缓存:

>>> from peak.util.proxies import LazyProxy

>>> def callback():
...     print("called!")
...     return 42

>>> lazy = LazyProxy(callback)
>>> lazy
called!
42
>>> lazy
42

可以在lazy上使用get_callbackset_callback函数 代理,但如果已经调用回叫,则不起作用:

>>> set_callback(lazy, lambda: 99)
>>> lazy
42

但是您可以使用get_cacheset_cache函数来篡改 缓存值:

>>> from peak.util.proxies import get_cache, set_cache
>>> get_cache(lazy)
42
>>> set_cache(lazy, 99)
>>> lazy
99

Wrappers

ObjectWrapperCallbackWrapperLazyWrapper类是 类似于他们的代理副本,除了他们打算 子类,以便添加自定义的额外属性或方法。任何属性 存在于这些类的子类中的将从 包装器实例,而不是包装对象。例如:

>>> from peak.util.proxies import ObjectWrapper
>>> class NameWrapper(ObjectWrapper):
...     name = None
...     def __init__(self, ob, name):
...         ObjectWrapper.__init__(self, ob)
...         self.name = name
...     def __str__(self):
...         return self.name

>>> w = NameWrapper(42, "The Ultimate Answer")
>>> w
42

>>> print(w)
The Ultimate Answer

>>> w * 2
84

>>> w.name
'The Ultimate Answer'

注意,您添加的任何属性都必须在类中定义。你不能 在运行时添加任意属性,因为它们将在包装的 对象而不是包装器:

>>> w.foo = 'bar'
Traceback (most recent call last):
  ...
AttributeError: 'int' object has no attribute 'foo'

注意,这意味着所有实例属性都必须实现为 插槽、属性或在类主体中定义了默认值(如 name = None如上图所示)。

CallbackWrapperLazyWrapper基类基本相同 作为ObjectWrapper,但它们使用回调或缓存的延迟回调 而不是期待一个对象作为他们的主题。

Creating Custom Subclasses and Mixins

除了上面描述的所有具体类之外,还有两个 抽象基类:AbstractProxyAbstractWrapper。如果你愿意 要创建一个可以与任何具体类型一起使用的MIXIN类型 应该将抽象版本子类化并将__slots__设置为空列表:

>>> from peak.util.proxies import AbstractWrapper

>>> class NamedMixin(AbstractWrapper):
...     __slots__ = []
...     name = None
...     def __init__(self, ob, name):
...         super(NamedMixin, self).__init__(ob)
...         self.name = name
...     def __str__(self):
...         return self.name

然后,当您将其与相应的基类混合时,可以将其添加回 任何必要的时隙,或者去掉__slots__以给出子类实例 字典他们自己的:

>>> from peak.util.proxies import CallbackWrapper, LazyWrapper

>>> class NamedObject(NamedMixin, ObjectWrapper): pass
>>> class NamedCallback(NamedMixin, CallbackWrapper): pass
>>> class NamedLazy(NamedMixin, LazyWrapper): pass

>>> print(NamedObject(42, "The Answer"))
The Answer

>>> n = NamedCallback(callback, "Test")
>>> n
called!
42
>>> n
called!
42

>>> n = NamedLazy(callback, "Once")
>>> n
called!
42
>>> n
42

AbstractProxyAbstractWrapper基类都由 假定^ TT31 } $将是已包装或代理的对象。如果 你不想用标准的三种方式来定义 __subject__(即作为对象、回调或延迟回调),您将需要 子类AbstractProxyAbstractWrapper并提供您自己的 定义__subject__的方式。

Mailing List

请将有关此包裹的问题直接发送到高峰邮件列表;请参阅 http://www.eby-sarna.com/mailman/listinfo/PEAK/了解详细信息。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
添加组件后,java JTable为空   java将json发送到php并插入mysql,但返回null   java Spring引导JNDI CommonJ资源   从不同PC创建和合并后的Java servlet问题   java如何在使用findelements时从xpath获取文本   java使用spring boot使用gmail smtp发送电子邮件   java在不使用pojo、bean或getter和setter的情况下获取Json标题的Json数组   Java中的OpenFile对话框将null作为响应   JavaBuilder模式。扩展接口   java中无需替换的数据结构选取   java如何评价Encog中的预测神经网络   java如何在安卓中使用实际的HttpURLConnection进行单元测试?   java使用XML配置禁用WebSocket中的CSRF保护   java如何通过hibernate从多表查询中获取数据?   mysql如何在java中获取更新的行Id   java AEM/CQ组件单一组件/有限组件   java FFmpeg Javacv延迟问题   显示整数数组的java不起作用