动态向类添加特殊方法无效

时间:2019-06-24 10:21:21

标签: python class operators

考虑此类,其中根据某些参数的值添加方法:

class Something(object):
    def __init__(self, value, op='+'):
        self.x = value
        if op == '+':
            self.add = self._operator
        elif op == '-':
            self.sub = self._operator

    def _operator(self, other):
        return self.x * other

x = Something(10)
x.add(3)
# 30

现在,我想使用+-运算符,而不是.add().sub()表示法。 为此,我会写:

class Something(object):
    def __init__(self, value, op='+'):
        self.x = value
        if op == '+':
            self.__add__ = self._operator
            self.__radd__ = self._operator
        elif op == '-':
            self.__sub__ = self._operator
            self.__rsub__ = self._operator

    def _operator(self, other):
        return self.x * other           

x = Something(10)
print(x + 3)

但是我得到的不是30

  

TypeError:+不支持的操作数类型:“ Something”和“ int”

尽管如此:

print(dir(x))
# ['__add__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__radd__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_operator', 'x']

出了什么问题,我该如何解决?

编辑

这与Overriding special methods on an instance的不同之处在于,在创建对象后,我不尝试向对象的实例添加特殊方法,即:

x = Something(10)
x.__add__ = ...

但是,在class.__init__()期间,虽然很公认,错误的来源和解决方案都非常相似。

2 个答案:

答案 0 :(得分:1)

特殊方法通常避免使用属性查找机制。他们不检查实例属性,而是直接在类中查找。

  

3.3.10. Special method lookup

     

对于自定义类,只有在对对象的类型(而不是在对象的实例字典中)进行定义的情况下,才能保证对特殊方法的隐式调用可以正常工作。

     

[...]

     

以这种方式绕过__getattribute__()机器为解释器内的速度优化提供了很大的空间,其代价是在处理特殊方法时需要一定的灵活性(必须设置特殊方法 在类对象本身上,以便被解释程序一致地调用。)

但是,您仍然可以使用特殊方法来引用实例属性。

扩展您的示例(可能会有更优雅的方式):

class Something(object):
    def __init__(self, value, op='+'):
        self.x = value
        if op == '+':
            self._add = self._operator
            self._radd = self._operator
        elif op == '-':
            self._sub = self._operator
            self._rsub = self._operator

    def _operator(self, other):
        return self.x * other

    def __add__(self, other):
        try:
            return self._add(other)
        except AttributeError:
            return NotImplemented

    # etc. for __radd__, __sub__ and __rsub__

x = Something(10)
print(x + 3)

答案 1 :(得分:0)

好吧,不要太在意,尽您所能,所以只需使用:

class Something(object):
    def __init__(self, value):
        self.x = value

    def __add__(self, other):
        return self.x * other

    def __sub__(self, other):
        return self.x * other

x = Something(10)
print(x + 3)

输出:

30

它也可以与-一起使用。