web-dev-qa-db-fra.com

L'héritage d'attributs utilisant __init__

Je suis Java personne qui vient de commencer à apprendre Python. Prenez cet exemple:

class Person():
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        self.name=name
        self.phone=phone
        self.website=website

Je suis sûr qu'il y a beaucoup de code redondant (je sais qu'en Java, il y a beaucoup de redondances pour le peu de code ci-dessus).

Quelles parties sont redondantes par rapport aux attributs déjà hérités de la classe parente?

39
user1111042

Lorsque vous écrivez la fonction __init__ Pour une classe en python, vous devez toujours appeler la fonction __init__ De sa superclasse. Nous pouvons l'utiliser pour passer les attributs pertinents directement à la superclasse, de sorte que votre code ressemblerait à ceci:

class Person(object):
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def __init__(self, name, phone, website):
        Person.__init__(self, name, phone)
        self.website=website

Comme d'autres l'ont souligné, vous pouvez remplacer la ligne

Person.__init__(self, name, phone)

avec

super(Teenager, self).__init__(name, phone)

et le code fera la même chose. C'est parce que dans python instance.method(args) est juste un raccourci pour Class.method(instance, args). Si vous voulez utiliser super vous devez vous assurer que vous spécifiez object comme classe de base pour Person comme je l'ai fait dans mon code.

La documentation python contient plus d'informations sur l'utilisation du mot clé super. L'important dans ce cas est qu'il indique python pour rechercher la méthode __init__ Dans une superclasse de self qui n'est pas Teenager

46
murgatroid99

Manière légèrement plus propre j'aime faire ça:

class Teenager(Person):
        def __init__(self, *args, **kwargs):
           self.website=kwargs.pop('website')
           super(Teenager, self).__init__(*args, **kwargs)

Cela ne fait pas beaucoup de différence dans ce cas, mais lorsque vous avez un __init__ avec une tonne d'arguments, cela vous facilite la vie.

15
Tom

Les attributs de Python ne sont pas hérités lorsqu'ils sont définis dans le constructeur et le constructeur de la classe parent n'est pas appelé, sauf si vous le faites tout manuellement:

class Person():
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def_init_(self, name, phone, website):
        Person.__init__(self, name, phone)  # Call parent class constructor.
        self.website=website

Plus d'informations ici: http://docs.python.org/tutorial/classes.html#inheritance

6
Mischa Arefiev

Jusqu'à présent, tous les exemples concernaient Python 2.x, mais voici une solution pour Python 3.x qui utilise une version plus courte de super ( ) et n'hérite pas de l'objet.

class Person:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        super().__init__(name, phone)
        self.website = website
5
Michael Kiros

__init__, Contrairement à un constructeur Java, n'est pas automatiquement appelé pour chaque classe de la hiérarchie d'héritage - vous devez le faire vous-même.

De plus, toutes vos hiérarchies d'objets doivent être enracinées dans object (sauf dans des cas particuliers).

Votre code doit lire:

class Person(object):
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def_init_(self, name, phone, website):
        super(Teenager, self).__init__(name, phone)
        self.website=website

super crée un délégué pour son deuxième argument (self), qui appellera la fonction suivante dans la liste des fonctions à appeler pour chaque nom (l '"ordre de résolution de méthode"). Ce n'est pas tout à fait la même chose que d'appeler la méthode superclasse, comme cela se produit en Java.

Vous pouvez également écrire super(type(self), self).__init__(name, phone), mais si vous héritez davantage de cette classe, type(self) peut ne pas être Teenager et vous pourriez avoir une récursion infinie. C'est une conséquence pratique du fait que vous travaillez avec un objet délégué avec une différence MRO, plutôt que d'appeler directement un constructeur de superclasse.

1
Marcin