Nick Craig-Wood wrote: > I've noticed with latest python 3.1 checkout (68631) if I have this > object hierarchy with a default __init__ in the superclass to be used > by the subclasses which don't necessarily need an __init__ it blows up > with a TypeError. > > class Field(object): object is default baseclass, hence not needed > def __init__(self, data): > """Default init for the subclasses""" > print("init class=%r, self=%r" % (self.__class__.__name__, self)) > super(Field, self).__init__(data) This line is the problem: remove it and I believe all is fine. Since object()s are immutable, its init cannot do anything as far as I know. Deleting this is effectively what you did below. Actually, I am puzzled why object even has __init__. Perhaps to avoid hasattr(ob,'__init__') check Doc implies that is it possible for a class to not have one. " object.__init__(self[, ...]) Called when the instance is created. The arguments are those passed to the class constructor expression. If a base class has an __init__() method, the derived class’s __init__() method, if any, must explicitly call it to ensure proper initialization of the base class part of the instance; for example: BaseClass.__init__(self, [args...]). As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime. " But in 3.0, *all* classes will inherit object.__init__. From super() doc... "There are two typical use cases for “super”. In a class hierarchy with single inheritance, “super” can be used to refer to parent classes without naming them explicitly, thus making the code more maintainable." I wonder about this claim. This use of super() does not eliminate the need to pass legal args, so you have to know what actually is called, so why not name it? > self.data = self.orig = data > > class IntegerField(Field): > def __init__(self, data): > """Overridden init""" ?? This over-rides and is not over-ridden. > super(IntegerField, self).__init__(data) > self.data = int(data) > > class StringField(Field): > pass > > f1 = StringField('abc') > f2 = IntegerField('10') > print("f1=%r" % f1.data) > print("f2=%r" % f2.data) > print(type(f1)) > print(type(f2)) > > It blows up with > > init class='StringField', self=<__main__.StringField object at 0xb7d47b4c> > Traceback (most recent call last): > File "subclass-super-problem-py3k.py", line 17, in <module> > f1 = StringField('abc') > File "subclass-super-problem-py3k.py", line 5, in __init__ > super(Field, self).__init__(data) > TypeError: object.__init__() takes no parameters > > The exact same code runs under py 2.5 just fine. Perhaps 2.5's object.__init__ just swallowed all args, thus hiding bogus calls. > I can't think of anything to write in Field.__init__ to tell whether > super is about to run __init__ on object. I do not understand. You know it is going to run the .__init__ of its one and only base class, which here is object. > The problem can be fixed (inelegantly IMHO) like this > > class BaseField(object): > def __init__(self, data): > """Default init for the subclasses""" > self.data = self.orig = data > > class Field(BaseField): > def __init__(self, data): > """Another Default init for the subclasses""" > super(Field, self).__init__(data) These two inits together are the original without bad call to object.__init__. No need to do this. > class IntegerField(Field): > def __init__(self, data): > """Overridden init""" > super(IntegerField, self).__init__(data) > self.data = int(data) > > class StringField(Field): > pass > > f1 = StringField('abc') > f2 = IntegerField('10') > print("f1=%r" % f1.data) > print("f2=%r" % f2.data) > print(type(f1)) > print(type(f2)) > > Is this a bug or a feature? Is there a better work-around? Eliminate bad call. Terry Jan Reedy
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4