编程语言
首页 > 编程语言> > python – 如何委托超类的__add__方法?

python – 如何委托超类的__add__方法?

作者:互联网

说我有这个班:

class MyString(str):
    def someExtraMethod(self):
        pass

我希望能够做到

a = MyString("Hello ")
b = MyString("World")
(a + b).someExtraMethod()
("a" + b).someExtraMethod()
(a + "b").someExtraMethod()

>按原样运行:

AttributeError: 'str' object has no attribute 'someExtraMethod'

>显然这不起作用.所以我补充一下:

def __add__(self, other):
    return MyString(super(MyString, self) + other)
def __radd__(self, other):
    return MyString(other + super(MyString, self))
TypeError: cannot concatenate 'str' and 'super' objects

>嗯,好的. super似乎不尊重运算符重载.也许:

def __add__(self, other):
    return MyString(super(MyString, self).__add__(other))
def __radd__(self, other):
    return MyString(super(MyString, self).__radd__(other))
AttributeError: 'super' object has no attribute '__radd__'

仍然没有运气.我该怎么办?

解决方法:

我通常使用super(MyClass,self).__方法__(其他)语法,在你的情况下这不起作用,因为str不提供__radd__.但是您可以使用str将类的实例转换为字符串.

谁说它的版本3工作:它没有:

>>> class MyString(str):
...     def __add__(self, other):
...             print 'called'
...             return MyString(super(MyString, self).__add__(other))
... 
>>> 'test' + MyString('test')
'testtest'
>>> ('test' + MyString('test')).__class__
<type 'str'>

如果你实现__radd__,你会得到一个AttributeError(参见下面的注释).

无论如何,我会避免使用内置函数作为基类型.正如您所看到的,某些细节可能很棘手,您还必须重新定义它们支持的所有操作,否则该对象将成为内置实例,而不是您类的实例.
我认为在大多数情况下使用委托而不是继承更容易.

此外,如果您只想添加单个方法,则可以尝试在纯字符串上使用函数.

我在这里添加了一些解释,为什么str不提供__radd__以及当python执行BINARY_ADD操作码(执行此操作的操作码)时会发生什么.

str .__ radd__的绝对是由于字符串对象实现了序列的连接运算符而不是数字加法运算.对于其他序列(例如列表或元组)也是如此.这些在“Python级别”是相同的,但实际上在C结构中有两个不同的“槽”.

python中的数字运算符由两个不同的方法(__ add__和__radd__)定义,实际上是一个单独的C函数,使用交换参数调用来模拟对__radd__的调用.

现在,你可以认为只实现MyString .__ add__会解决你的问题,因为str没有实现__radd__,但事实并非如此:

>>> class MyString(str):
...     def __add__(self, s):
...             print '__add__'
...             return MyString(str(self) + s)
... 
>>> 'test' + MyString('test')
'testtest'

你可以看到MyString .__ add__没有被调用,但如果我们交换参数:

>>> MyString('test') + 'test'
__add__
'testtest'

它被称为,所以发生了什么?

答案是在documentation中指出:

For objects x and y, first x.__op__(y) is tried. If this is not
implemented or returns NotImplemented, y.__rop__(x) is tried. If this
is also not implemented or returns NotImplemented, a TypeError
exception is raised. But see the following exception:

Exception to the previous item: if the left operand is an instance of
a built-in type or a new-style class, and the right operand is an
instance of a proper subclass of that type or class and overrides the
base’s __rop__() method, the right operand’s __rop__() method is tried
before the left operand’s __op__() method.

This is done so that a subclass can completely override binary
operators. Otherwise, the left operand’s __op__() method would always
accept the right operand: when an instance of a given class is
expected, an instance of a subclass of that class is always
acceptable.

这意味着你必须实现str和__r * __方法的所有方法,否则你仍然会遇到参数顺序问题.

标签:python,oop,inheritance,override,delegation
来源: https://codeday.me/bug/20190716/1479983.html