python - 我如何委托(delegate)给父类(super class)的 __add__ 方法?

标签 python oop inheritance overriding delegation

假设我有这个类:

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

我希望能够做到

a = MyString("Hello ")
b = MyString("World")
(a + b).someExtraMethod()
("a" + b).someExtraMethod()
(a + "b").someExtraMethod()
  1. 按原样运行:

    AttributeError: 'str' object has no attribute 'someExtraMethod'
    
  2. 显然这行不通。所以我添加这个:

    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
    
  3. 嗯,好的。 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).__method__(other) 语法,在你的情况下这不起作用,因为 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(见下面的注释)。

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

此外,如果您只想添加一个方法,那么您可以尝试在纯字符串上使用函数。


我在这里添加了一些关于为什么 str 不提供 __radd__ 以及当 python 执行 BINARY_ADD 操作码(the一个执行 + 的)。

str.__radd__ 的缺失是因为字符串对象实现了序列的连接运算符,而不是数字加法运算。其他序列也是如此,例如 listtuple。这些在“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 - 我如何委托(delegate)给父类(super class)的 __add__ 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13343857/

相关文章:

python - 检查数据帧列中的值是否在列表中 - Python

php oop - 强制静态方法的参数成为当前类的对象

c# - 为什么不允许在派生接口(interface)上显式实现基接口(interface)的方法?

oop - 什么是委托(delegate)?

java - 类构造函数中的字段初始化 : direct or through "setter"?

delphi - TFrame继承重构

C#:通用继承工厂

python - 提取单词后的所有行

python - 如何将数据发布到网站并立即将您重定向到另一个网站

Python Procedural 2d map 生成器说明