通用代理和包装器类型
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_callback和set_callback函数 代理,但如果已经调用回叫,则不起作用:
>>> set_callback(lazy, lambda: 99) >>> lazy 42
但是您可以使用get_cache和set_cache函数来篡改 缓存值:
>>> from peak.util.proxies import get_cache, set_cache >>> get_cache(lazy) 42 >>> set_cache(lazy, 99) >>> lazy 99
Wrappers
ObjectWrapper、CallbackWrapper和LazyWrapper类是 类似于他们的代理副本,除了他们打算 子类,以便添加自定义的额外属性或方法。任何属性 存在于这些类的子类中的将从 包装器实例,而不是包装对象。例如:
>>> 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如上图所示)。
CallbackWrapper和LazyWrapper基类基本相同 作为ObjectWrapper,但它们使用回调或缓存的延迟回调 而不是期待一个对象作为他们的主题。
Creating Custom Subclasses and Mixins
除了上面描述的所有具体类之外,还有两个 抽象基类:AbstractProxy和AbstractWrapper。如果你愿意 要创建一个可以与任何具体类型一起使用的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
AbstractProxy和AbstractWrapper基类都由 假定^ TT31 } $将是已包装或代理的对象。如果 你不想用标准的三种方式来定义 __subject__(即作为对象、回调或延迟回调),您将需要 子类AbstractProxy或AbstractWrapper并提供您自己的 定义__subject__的方式。
Mailing List
请将有关此包裹的问题直接发送到高峰邮件列表;请参阅 http://www.eby-sarna.com/mailman/listinfo/PEAK/了解详细信息。