Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 动态添加内置方法以指向属性';内置的_Python_Partial Application - Fatal编程技术网

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')