支持稍加修改的对象重用

dm.reuse的Python项目详细描述


在新上下文中重用(稍微修改)对象的实用程序。

目前,有两个实用程序:rebindFunctionOverridingProxy

rebindFunction

rebindFunction允许在更改时重用函数的代码 名称、全局参数、默认参数、属性和/或使用的名称。

让我们看一个小例子。函数f访问全局变量 ij

示例

>>> i = 1; j = 2
>>> def f(): return i, j
...
>>> f()
(1, 2)

我们想得到一个新的函数g,它将i绑定到-1

>>> from dm.reuse import rebindFunction
>>> g=rebindFunction(f, i=-1)
>>> g()
(-1, 2)

我们不仅可以通过关键字参数,还可以通过 还有一本字典:

>>> g=rebindFunction(f, dict(i=-1, j=-2))
>>> g()
(-1, -2)

通常,函数名是从原来的函数取而代之的, 但可以更改:

>>> f.__name__
'f'
>>> g.__name__
'f'
>>> g=rebindFunction(f, dict(i=-1, j=-2), funcName='g')
>>> g.__name__
'g'
>>> g()
(-1, -2)

原始函数docstring也被接管,除非 覆盖:

>>> f.func_doc = 'some documentation'
>>> g=rebindFunction(f, dict(i=-1, j=-2))
>>> f.__doc__ is g.__doc__
True
>>> g=rebindFunction(f, dict(i=-1, j=-2), funcDoc='some new documentation')
>>> g.__doc__
'some new documentation'

可以添加、删除或更改参数的默认值。 可识别未知参数:

>>> def f(a1, a2=2): return a1, a2
...
>>> g=rebindFunction(f, argRebindDir=dict(a1=1))
>>> g()
(1, 2)
>>> from dm.reuse import REQUIRED
>>> g=rebindFunction(f, argRebindDir=dict(a2=REQUIRED))
>>> g(1) #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
  ...
TypeError: f() takes exactly 2 arguments (1 given)
>>> g=rebindFunction(f, argRebindDir=dict(a2=10))
>>> g(1)
(1, 10)
>>> g=rebindFunction(f, argRebindDir=dict(a3=10))
Traceback (most recent call last):
  ...
ValueError: unknown arguments in `argRebindDir`: a3

最后,函数属性可以通过proprebinddir反弹。 我们很小心,给新函数一个单独的新属性dict。

>>> f.prop='p'
>>> g=rebindFunction(f)
>>> g.prop
'p'
>>> g=rebindFunction(f, propRebindDir=dict(prop='P', prop2='p2'))
>>> g.prop, g.prop2
('P', 'p2')
>>> f.__dict__
{'prop': 'p'}

有时,函数使用的本地导入不充分 在新的背景下。为了控制他们,名字 在函数代码内部使用可以更改。

>>> def f(a): import codecs; return codecs, a
...
>>> g=rebindFunction(f, nameRebindDir=dict(codecs='urllib'))
>>> r = g(1)
>>> r[0].__name__, r[1]
('urllib', 1)

这样,对全局变量的引用也可以更改。

>>> i1, i2 = 1, 2
>>> def f(): return i1
...
>>> g=rebindFunction(f, nameRebindDir=dict(i1='i2'))
>>> g()
2

OverridingProxy

有时,您必须使用一个对象,该对象的总体功能 基本上是足够的,但小的方面需要改变。 在这些情况下,OverridingProxy可能会有帮助。它允许 代理对象。代理主要表现为代理 对象,但某些属性/方法被重写。

示例

我们设置了一个play对象c,并假装必须使用它 使用修改后的属性attr1。我们通过代理来实现这一点 它的行为类似于c,但属性已更改。

>>> from dm.reuse.proxy import OverridingProxy, make_proxy
>>>
>>> class C(object):
...   attr1 = 1
...   attr2 = 2
...   def f(self): return self.attr1, self.attr2
...   def g(self): return self.f()
...
>>> c = C()
>>> p = make_proxy(c, attr1='overridden attr1')
>>> p.__class__ is C
True
>>> isinstance(p, C)
True
>>> p.attr1
'overridden attr1'

当我们调用使用 过度驾驶属性。

>>> p.f()
('overridden attr1', 2)

如果我们为代理属性分配一个新值,那么 代理对象上的相应属性被更改。 因此,更改重写的属性 显然没有效果-这不直观,可能会改变 未来。

>>> p.attr2 = "new attr2"
>>> p.f()
('overridden attr1', 'new attr2')
>>> p.attr1 = "new attr1"
>>> c.attr1
'new attr1'
>>> p.f()
('overridden attr1', 'new attr2')

您可以使用方法set_proxy_attribute来更改 代理的属性而不是代理方法的属性。

>>> p.set_proxy_attribute("attr1", "new overridden attr1")
>>> p.f()
('new overridden attr1', 'new attr2')

一个代理比较通常等于它的代理对象。有时候, 这也适用于相反的情况。但是,两个 对于同一代理对象的代理比较通常是相等的。

>>> p == c
True
>>> c == p
True
>>> make_proxy(c) == p
True

通常,您不会重写简单的属性,而是重写方法。 使用自定义代理类更容易实现这一点。 在许多情况下,重写方法将要调用 重写的方法;这可以通过call_proxied_method实现。

>>> class MyProxy(OverridingProxy):
...   def g(self):
...     print ("g called")
...     return self.call_proxied_method("g")
...
>>> p = make_proxy(c, MyProxy, attr1="overridden attr1")
>>> p.g()
g called
('overridden attr1', 'new attr2')
P>代理对特殊方法的支持有限 从而支持例如订阅。注意这个支持 是不完整的,可能会有惊喜。

>>> class MyDict(dict, C): pass
...
>>> md = MyDict(dict(a=1, b=2))
>>> p = make_proxy(md, attr1="overridden attr1")
>>> p.f()
('overridden attr1', 2)
>>> p["a"]
1
>>> class MySequence(C):
...   seq = 0, 1, 2
...   def __getitem__(self, i): return self.seq[i]
...
>>> c = MySequence()
>>> p = make_proxy(c, seq=(10, 11, 12))
>>> p[0]
10
>>> p = make_proxy(c)
>>> p[0]
0

通常,描述符也会看到修改后的状态。

>>> class WithProperty(C):
...   @property
...   def attr1_prop(self): return self.attr1
...
>>> c = WithProperty()
>>> p = make_proxy(c, attr1="overridden attr1")
>>> p.attr1_prop
'overridden attr1'

历史记录

2.1
添加了OverridingProxy,允许使用 小改动
2.0

添加了对python 3的部分支持(仅限关键字参数和 尚未支持批注)

在2.7之前放弃了对python的支持

1.1
nameRebindDir支持已添加

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

推荐PyPI第三方库


热门话题
NetBeans中的Java Swing滚动窗格   java如何与具有复合键的表建立关系?   Android中读取文件时java数据丢失   java黄瓜场景。embed在ubuntu机器上不工作?   java从spring mvc控制器操作中,我如何获得请求/响应的访问权限?   java减去两个长值   java选择下一个值firebase 安卓   用于起始和结尾连字符的java正则表达式   Java正则表达式解释   java Lifefay freemarker ADT:方法不可用?   java我怎样才能让我的开关盒作用于JFrame?   java在我的场景中使用连接池的理想方式是什么   java我如何接受jsoup的cookies?   java如何将整数数组更改为字符串数组?   java Android操作\u指针\u向上直到剩余触摸移动时才调用   java为什么gradle会出错?   io如何在java中复制/拆分输入流?   java使JButton不可见,但尊重其原始空间   java Spring提交表单获取复选框值不起作用