通用代理和包装器类型

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 JAXB封送字符串,具有xml值,且不转义该值   java ModelMapper转换器不工作   java像HH000412或HCANN000001这样的前缀是什么意思?   验证日期输入修复java。lang.numberformatexception错误   当表具有外键时,java Telosys代码生成失败   如何使所有派生类一起只能实例化一个实例的单例抽象基类?(爪哇)   java如何在非静态服务类中使用广播接收器   java nutch爬虫相对URL问题   使用Jboss DMR下载/保存java附件   Rest模板:无法提取响应:当我们得到xml响应时,没有找到适合响应类型的HttpMessageConverter,没有绑定到JAVA对象   java如何编写可扩展窗格/面板/卡的代码   java是在ITreeViewerListener的treeExpanded()之前调用ContentProvider的getChildren()吗?   java将JComponent添加到小程序窗格   java混淆:使用简单逻辑的Flames程序