Python的多重继承__new__和__init__带有字符串和第二类

时间:2013-05-30 18:12:02

标签: python inheritance multiple-inheritance super abc

我正在尝试创建一个继承自str类型和第二类的派生类。这是有问题的,因为str类型不是简单地调用__init__,而是__new__方法由于其不变性。我知道,对于__init__和super工作得很好,你需要一直保持相同的调用结构。但是,以下实现失败:

class base(object):
    def __new__(cls, *args, **kwargs):
        print "NEW  BASE:", cls, args, kwargs
        return super(base, cls).__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        print "INIT BASE", args, kwargs

class foo(base, str):
    def __new__(cls, *args, **kwargs):
        return super(foo, cls).__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        super(foo, self).__init__(*args, **kwargs)

此处foo('cat')适用于:

>> NEW  BASE: <class '__main__.foo'> ('cat',) {}
>> INIT BASE ('cat',) {}

但是使用参数foo('cat', x=3),它会失败:

>> NEW  BASE: <class '__main__.foo'> ('cat',) {'x': 3}
Traceback (most recent call last):
  File "inh.py", line 19, in <module>
    foo('cat', x=3)
  File "inh.py", line 12, in __new__
    return super(foo, cls).__new__(cls, *args, **kwargs)
  File "inh.py", line 4, in __new__
    return super(base, cls).__new__(cls, *args, **kwargs)
TypeError: str() takes at most 1 argument (2 given)

可以通过将base.__new__方法更改为

来实现此功能
def __new__(cls, *args, **kwargs):
    return super(base, cls).__new__(cls)

但是现在我已经改变了调用结构,我觉得这会让我后来遇到问题。

如何正确地继承字符串和第二类

1 个答案:

答案 0 :(得分:2)

你不能只做

def __new__(cls, *args, **kwargs):
    return super(base, cls).__new__(cls)

因为这会导致对str的 new 的错误调用(您不会传递允许的参数

>>> foo('t')
NEW  BASE: <class '__main__.foo'> ('t',) {}
INIT BASE ('t',) {}
''

您应该执行类似

的操作
def __new__(cls, *args, **kwargs):
    return super(base, cls).__new__(cls, *args[:1])

但如果您将base类用作mixin,__new__方法接受多个参数,那么这可能会破坏某些内容。

作为一个选项也许你应该让类继承自str但是重写了 new 方法:

class CarelessStr(str):
    def __new__(cls, *args, **kwargs):
        return super(CarelessStr, cls).__new__(cls, *args[:1])

class foo(base, CarelessStr):
    def __new__(cls, *args, **kwargs):
        return super(foo, cls).__new__(cls, *args, **kwargs)

    def __init__(self, *args, **kwargs):
        super(foo, self).__init__(*args, **kwargs)