如何(或为何不)从子类调用unicode.__init__
我遇到了一个情况,就是在Python 3.3之前,继承unicode会出现弃用警告,而在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 个回答
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__
)。