假设我有这个类:
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).__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__
的缺失是因为字符串对象实现了序列的连接运算符,而不是数字加法运算。其他序列也是如此,例如 list
或 tuple
。这些在“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
andy
, firstx.__op__(y)
is tried. If this is not implemented or returnsNotImplemented
,y.__rop__(x)
is tried. If this is also not implemented or returnsNotImplemented
, aTypeError
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/