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

How to (or why not) call unicode.__init__ from subclass

我遇到过这样一种情况:子类化Unicode会导致3.3之前的python警告和3.3之前的python错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 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的输出。

1
2
3
4
5
> 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)

代码被简化以举例说明这个问题。在实际应用程序中,我执行的不仅仅是调用super __init__

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

为什么可以在Unicode实例上调用unicode.__init__,而不是在Unicode子类上调用unicode.__init__?如果对unicode类进行子类化,作者应该怎么做?


我怀疑这个问题是因为unicode是不变的。

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

不可变类型的子类没有相同的严格要求,因此如果需要,可以在unicode2.__init__中执行操作,但调用unicode.__init__是不必要的(而且可能不会执行您认为它会执行的操作)。

更好的解决方案可能是使用您自己的__new__方法进行定制逻辑:

1
2
3
4
5
6
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__方法使其不可变(您还可以通过省略每个实例的__dict__给类一个__slots__属性来保存内存)。