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

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to