【问题标题】:Dynamically add special methods to class does not work [duplicate]向类动态添加特殊方法不起作用[重复]
【发布时间】:2019-06-24 10:21:21
【问题描述】:

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

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__() 期间,尽管无可否认,错误的来源和解决方案都非常相似。

【问题讨论】:

    标签: python class operators


    【解决方案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)
    

    【讨论】:

      【解决方案2】:

      好吧,别那么麻烦,尽你所能,所以就用吧:

      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
      

      它也适用于-

      【讨论】:

      • 此解决方法不能解决原始问题。此外,在类的主体上使用__sub__ = __add__ 会更优雅。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-17
      • 2017-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多