如何(或为什么不)从子类调用unicode .__ init__

时间:2013-02-09 00:49:53

标签: python constructor subclass

我遇到过一种情况,即子类化unicode会导致3.3之前的Python上的弃用警告和Python 3.3上的错误:

# prove that unicode.__init__ accepts parameters
s = unicode('foo')
s.__init__('foo')
unicode.__init__(s, 'foo')

class unicode2(unicode):
    def __init__(self, other):
        super(unicode2, self).__init__(other)

s = unicode2('foo')

class unicode3(unicode):
    def __init__(self, other):
        unicode.__init__(self, other)

s = unicode3('foo')

奇怪的是,前三行中没有出现警告/错误,而是出现在第8行和第14行。这是Python 2.7的输出。

> python -Wd .\init.py
.\init.py:8: DeprecationWarning: object.__init__() takes no parameters
  super(unicode2, self).__init__(other)
.\init.py:14: DeprecationWarning: object.__init__() takes no parameters
  unicode.__init__(self, other)

简化代码以举例说明问题。在现实世界的应用程序中,我执行的不仅仅是调用超级__init__

从前三行开始,unicode类实现__init__,并且该方法至少接受一个参数。但是,如果我想从子类调用该方法,我似乎无法这样做,无论我是否调用super()

为什么在unicode实例上调用unicode.__init__而在unicode子类上调用却没问题?如果继承unicode类,作者要做什么?

1 个答案:

答案 0 :(得分:4)

我怀疑问题来自于unicode是不可变的事实。

创建unicode实例后,无法修改它。因此,任何初始化逻辑都将在__new__方法(调用它来进行实例创建)中,而不是__init__(仅在实例存在后调用)。

不可变类型的子类没有相同的严格要求,因此如果需要,可以在unicode2.__init__中执行操作,但调用unicode.__init__是不必要的(并且可能不会执行你认为无论如何都会这样做。)

更好的解决方案可能是在您自己的__new__方法中执行自定义逻辑:

class unicode2(unicode):
    def __new__(cls, value):
        # optionally do stuff to value here
        self = super(unicode2, cls).__new__(cls, value)
        # optionally do stuff to self here
        return self

如果你愿意的话,你也可以让你的类不可变,给它一个总是引发异常的__setattr__方法(你可能也想给这个类一个__slots__属性以节省内存省略每个实例__dict__)。