通用代理和包装器类型。

proxytypes3的Python项目详细描述


简单代理类型

Build Status

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

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

这个包是peak.util.proxies模块的叉, 扩展到支持Python3.*以及更好的测试和持续集成。

代理基础知识

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

>>> from proxytypes3 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

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

>>> p.__subject__
42

>>> type(p)
<class 'proxytypes3.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
< H2>回调代理< /H2>

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

>>> from proxytypes3 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代理 跑进去。

可以通过get_callback获取或更改回调代理的回调。 以及set_callback函数:

>>> from proxytypes3 import get_callback, set_callback
>>> set_callback(counter, lambda: 42)

>>> counter
42

>>> get_callback(counter)
<function <lambda> at ...>
< H2>懒惰代理< /H2>

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

>>> from proxytypes3 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 proxytypes3 import get_cache, set_cache
>>> get_cache(lazy)
42
>>> set_cache(lazy, 99)
>>> lazy
99

包装纸

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

>>> from proxytypes3 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,除了它们使用回调或缓存的延迟回调 而不是期待一个对象作为他们的主题。

< H2>创建自定义子类和MIXIN < /H2>

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

>>> from proxytypes3 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 proxytypes3 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基类都由 假定^ {CD3}}将是被包装或代理的对象。如果 你不想用标准的三种方式来定义 __subject__(即作为对象、回调或延迟回调),您将需要 子类AbstractProxyAbstractWrapper并提供您自己的 定义__subject__的方法。

测试

要跨多个python版本运行unittests,首先安装必要的python版本。在ubuntu上,运行:

sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt-get update
sudo apt-get install python-dev python3.4-minimal python3.4-dev python3.5-minimal python3.5-dev python3.6 python3.6-dev

然后运行所有tests

tox

为特定环境(如Python2.7)运行测试:

tox -e py27

运行特定测试:

export TESTNAME=.additional_tests; tox -e py34

export TESTNAME=.TestObjectProxy.testNumbers; tox -e py36

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

推荐PyPI第三方库


热门话题
java是IO流上的通道包装器吗?   如何向java添加助记符。awt。菜单   使用Apache Commons电子邮件库在Java中发送电子邮件时发生身份验证错误   java在处理更新时合并到文件中   java格式化双精度且不舍入   java Freemarker有没有办法将整数格式化为浮点数?   在Grails Spring数据应用程序中混合java和groovy代码时出错   Java NIO将文件移动到共享位置   在Java中,main方法返回值64而不是100。为什么会这样?   javac java错误:无法找到或加载主类ass1。插入   如何在从客户机(Java、Socket)接收特定消息时自动返回响应   在安卓上创建两次java活动   java Comed+selenium。客户端通信不稳定   java想将值发送到cmd,不知道命令或如何发送   java如何将SQL查询转换为JSON数组   用Java绘制多段线的图形   私有Java setter不会更改整数的值   java CWWMQ0062E:从IBM队列连接工厂启用SSL时接收错误   在运行时更改java swing中的语言   java Android Eclipse在执行时“未找到源”