Eri*_*ric 3 python oop inheritance overriding delegation
说我有这个班:
class MyString(str):
def someExtraMethod(self):
pass
Run Code Online (Sandbox Code Playgroud)
我希望能够做到
a = MyString("Hello ")
b = MyString("World")
(a + b).someExtraMethod()
("a" + b).someExtraMethod()
(a + "b").someExtraMethod()
Run Code Online (Sandbox Code Playgroud)
按原样运行:
AttributeError: 'str' object has no attribute 'someExtraMethod'
Run Code Online (Sandbox Code Playgroud)显然这不起作用.所以我补充一下:
def __add__(self, other):
return MyString(super(MyString, self) + other)
def __radd__(self, other):
return MyString(other + super(MyString, self))
Run Code Online (Sandbox Code Playgroud)
TypeError: cannot concatenate 'str' and 'super' objects
Run Code Online (Sandbox Code Playgroud)嗯,好的.super
似乎不尊重运算符重载.也许:
def __add__(self, other):
return MyString(super(MyString, self).__add__(other))
def __radd__(self, other):
return MyString(super(MyString, self).__radd__(other))
Run Code Online (Sandbox Code Playgroud)
AttributeError: 'super' object has no attribute '__radd__'
Run Code Online (Sandbox Code Playgroud)仍然没有运气.我该怎么办?
我通常使用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'>
Run Code Online (Sandbox Code Playgroud)
如果你实施,__radd__
你得到一个AttributeError
(见下面的注释).
无论如何,我会避免使用内置函数作为基类型.正如您所看到的,某些细节可能很棘手,您还必须重新定义它们支持的所有操作,否则该对象将成为内置实例,而不是您类的实例.我认为在大多数情况下使用委托而不是继承更容易.
此外,如果您只想添加单个方法,则可以尝试在纯字符串上使用函数.
我在这里添加了一些解释,说明为什么str
不提供__radd__
以及当python执行BINARY_ADD
操作码(执行操作的操作码)时会发生什么+
.
的abscence 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'
Run Code Online (Sandbox Code Playgroud)
你可以看到MyString.__add__
没有调用,但如果我们交换参数:
>>> MyString('test') + 'test'
__add__
'testtest'
Run Code Online (Sandbox Code Playgroud)
它被称为,所以发生了什么?
答案在文件中指出:
对于对象
x
和y
,首先x.__op__(y)
是尝试.如果没有实现或返回NotImplemented
,y.__rop__(x)
则尝试.如果这也没有实现或返回NotImplemented
,TypeError
则引发异常.但请参阅以下异常:前一项的异常:如果左操作数是内置类型或新样式类的实例,并且右操作数是该类型或类的正确子类的实例并覆盖基类的
__rop__()
方法,则右操作数的__rop__()
方法在左操作数的__op__()
方法之前尝试.这样做是为了使子类可以完全覆盖二元运算符.否则,左操作数的
__op__()
方法将始终接受右操作数:当期望给定类的实例时,该类的子类的实例始终是可接受的.
这意味着你必须实现所有的方法str
和该__r*__
方法,否则,你仍然有争论订单的问题.