I’ve encountered a situation where subclassing unicode results in Deprecation Warnings on Python prior to 3.3 and errors on 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')
Curiously, the warnings/errors don’t occur in the first three lines, but instead occur on lines 8 and 14. Here’s the output on 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)
The code is simplified to exemplify the issue. In a real-world application, I would perform more than simply calling the super __init__.
It appears from the first three lines that the unicode class implements __init__ and that method accepts at least a single parameter. However, if I want to call that method from a subclass, I appear to be unable to do so, whether I invoke super() or not.
Why is it okay to call unicode.__init__ on a unicode instance but not on a unicode subclass? What is an author to do if subclassing the unicode class?
I suspect the issue comes from the fact that
unicodeis immutable.After a
unicodeinstance is created, it cannot be modified. So, any initialization logic is going to be in the__new__method (which is called to do the instance creation), rather than__init__(which is called only after the instance exists).A subclass of an immutable type doesn’t have the same strict requirements, so you can do things in
unicode2.__init__if you want, but callingunicode.__init__is unnecessary (and probably won’t do what you think it would do anyway).A better solution is probably to do your customized logic in your own
__new__method:You can make your class immutable too, if you want, by giving it a
__setattr__method that always raises an exception (you might also want to give the class a__slots__property to save memory by omitting the per-instance__dict__).