nested constructor. Why is it required?

2019-07-14 22:37发布

问题:

class Character(Entity):
    def __init__(self, x, y, hp):
        Entity.__init__(self, x, y)
        self.hp = hp
        self.items = []

Character is a child class of the parent class Entity. Entity class also has a __init__ function. Why is there a need to write both the __init__ functions? Why not only write the __init__() for the Character class, which would overwrite the __init__() for Entity?

回答1:

It depends what happens in Entity.__init__! If (and only if) all it does is set self.x and self.y, you could do:

class Character(Entity):
    def __init__(self, x, y, hp):
        self.x = x
        self.y = y
        self.hp = hp
        self.items = []

But this is one line longer already, and if anything else other than setting arguments to instance attributes gets done in Entity.__init__ (like, for example, self.items = [] in Character.__init__) your Character may not work properly.

It is good practice to call the super-class's __init__ method, to make sure that everything that needs to be done gets done.

You can make your code more general using super:

class Character(Entity):
    def __init__(self, x, y, hp):
        super(Character, self).__init__(x, y)

So that if you change what Character inherits from your __init__ still works.



回答2:

You can do that but then you won't be calling the constructor of the superclass (Entity). In that case it's up to your constructor to make sure the object ends up in a consistent state.

The alternative is to call the constructor of the superclass and then perform some further actions that are needed for a Character instance. This means you'll already have an object in a consistent state (after the Entity constructor is finished) and you're only making further adjustments that are specific to Character objects.



回答3:

Why is there a need to write both the __init__ functions?

There isn’t. You’re doing two completely different things here:

  • You define Character.__init__, and
  • You call Entity.__init__.

As you’ve noticed yourself, Character’s __init__ method overrides Entity’s. So if you want to invoke that, you need to call it explicitly from within Character’s now.



回答4:

That depends on what the classes are supposed to do.

If we suppose that the classes initiate their own stuff respectively, then you see that

  • Entity inits its own attributes x and y and
  • Character inits its additional attributes hp and items.

You could put the initialization of x and y to Character as well, but then what about Entity itself and tis other child classes?



回答5:

Without adding to what is already said above - it is a common mistake to call __init__ method a constructor - but it is not!
Constructor is a __new__ method, and is seldom used. Python documentation is a little bit cryptic on the issue - see here, but it never calls it constructor directly. Why? Constructor - in the standard OOP terminology, creates class instance - object - and returns it. __init__ simply does not do it!