我遇到过一种情况,即子类化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类,作者要做什么?
答案 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__
)。