Python 动态添加内置方法以指向属性';内置的
我有两个类和一个函数:Python 动态添加内置方法以指向属性';内置的,python,partial-application,Python,Partial Application,我有两个类和一个函数: from functools import partial def fn(other, self, name): print(f"calling {name} with {other}") func = getattr(self.a, name) return func(other) class A: def __add__(self, other): return 9 def __mul__(self,
from functools import partial
def fn(other, self, name):
print(f"calling {name} with {other}")
func = getattr(self.a, name)
return func(other)
class A:
def __add__(self, other):
return 9
def __mul__(self, other):
return 7
def __sub__(self, other):
return 8
class B:
def __init__(self,a):
self.a = a
for name in ['add', 'sub']:
name = f"__{name}__"
p = partial(fn, self=self,name=name)
setattr(self, name, p)
p.__name__ = name
我希望能够使用将魔术方法转发到现有属性。我不想继承这个类,因为我不想要所有的内置项。就一对。例如,我可能想使用另一个类中的multiply。我试图避免这样编码:
def __add__(self, other):
self.a.__add__(other)
使用上述代码,我收到以下信息:
>>> b = B(A())
>>> b + 3
TypeError Traceback (most recent call last)
<ipython-input-40-fa904b7bb783> in <module>
----> 1 b + 3
2
TypeError: unsupported operand type(s) for +: 'B' and 'int'
>>> b.__add__(3)
calling __add__ with 3
9
>b=b(A())
>>>b+3
TypeError回溯(最近一次调用上次)
在里面
---->1 b+3
2.
TypeError:不支持+:“B”和“int”的操作数类型
>>>b.(三)
用3调用_u添加_uu
9
也许我遗漏了一些简单的东西,但我找不到一种动态添加内置函数的方法。要解决的主要问题是,像
\uuuuuuu add\uuu
这样的神奇方法是在类上查找的,而不是在对象本身上;否则,您可以在\uuuu init\uuu
方法中编写self.\uuuu添加=a.\uuuu添加
。为了解决这个问题,我们需要在类B
上声明方法,而不是在单个实例上声明方法
下面定义的函数delegate
通过向B
类添加一个方法来工作。此方法采用self
,这将是B
实例,因此它必须动态加载a
属性,然后加载其\uuuuuu添加
方法
A类:
定义添加(自身、其他):
返回9
定义多个(自身、其他):
返回7
定义(自身、其他):
返回8
B类:
定义初始化(self,a):
self.a=a
def委托(cls、属性名称、方法名称):
授权def(自我、*VARG、**kwargs):
a=getattr(self,attr\u name)
m=getattr(a,方法名称)
返回m(*vargs,**kwargs)
setattr(cls,方法名称,委托)
委托人(B,‘a’,‘添加’
代表(B,‘a’、‘子’
例如:
>b=b(A())
>>>b+3
9
>>>b-4
8.
代理\uuu dunder\uuu
方法很棘手。我将使用描述符对象,与其他方法相比,它将更干净地处理潜在的属性访问奥秘
class Proxy:
def __set_name__(self, owner, name):
self.attr = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
try:
proxy = obj._proxy
except AttributeError:
raise AttributeError('tried to access proxy field on object with no _proxy')
return getattr(proxy, self.attr)
class A:
def __add__(self, other):
return 9
def __mul__(self, other):
return 7
def __sub__(self, other):
return 8
class B:
def __init__(self,a):
self.a = a
self._proxy = self.a
__add__ = Proxy()
__sub__ = Proxy()
b = B(A())
ipython repl中的一个示例:
In [6]: b = B(A())
In [7]: b + b
Out[7]: 9
In [8]: b - b
Out[8]: 8
In [9]: b * b
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-19-cb34cccc83f5> in <module>
----> 1 b * b
TypeError: unsupported operand type(s) for *: 'B' and 'B'
很公平。不过,我喜欢你的解决方案,我想如果你愿意,你可以在你的
代理
类中添加一个attr_name
,并动态加载它,以允许将不同的方法委托给不同的属性。是的,它绝对是可扩展的。
class Proxy:
def __init__(self, proxy_field):
self.prox_field = proxy_field
def __set_name__(self, owner, name):
self.attr = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
try:
proxy = getattr(obj, self.proxy_field)
except AttributeError:
raise AttributeError(f'tried to access proxy field on object with no {self.proxy_field} attribute')
return getattr(proxy, self.attr)
class B:
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
__add__ = Proxy('foo')
__sub__ = Proxy('bar')