ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-07-16 16:56:35  阅读:241  来源: 互联网

标签:python oop inheritance override delegation


说我有这个班:

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有