Python: Comment créer une sous-classe à partir d'une superclasse?

86

En Python, comment créer une sous-classe à partir d'une superclasse?

dave.j.lott
la source
3
Notez que le Python a changé la façon dont vous faites des sous-classes, il y a donc 2 façons de le faire, et elles ne se mélangent pas. Vous obtiendrez une erreur si vous mélangez. Lisez cet article pour voir la différence: stackoverflow.com/questions/1713038/…
Mark Lakata

Réponses:

89
# Initialize using Parent
#
class MySubClass(MySuperClass):
    def __init__(self):
        MySuperClass.__init__(self)

Ou, encore mieux, l'utilisation de la fonction intégrée de Python super()(voir la documentation Python 2 / Python 3 pour cela) peut être une méthode légèrement meilleure pour appeler le parent pour l'initialisation:

# Better initialize using Parent (less redundant).
#
class MySubClassBetter(MySuperClass):
    def __init__(self):
        super(MySubClassBetter, self).__init__()

Ou, exactement la même chose que juste ci-dessus, sauf en utilisant la forme d'argument zéro de super(), qui ne fonctionne que dans une définition de classe:

class MySubClassBetter(MySuperClass):
    def __init__(self):
        super().__init__()
thompsongunner
la source
6
OTOH, certaines personnes déconseillent super, en particulier pour les nouveaux programmeurs Python (par exemple, Lutz). Je l'évite.
eric
6
La seule raison à éviter superest si vous ne comprenez pas les différences entre la façon dont superfonctionne en Python et comment super/ parentfonctionne dans d'autres langages. Certes, ce n'est pas évident pour les personnes venant d'autres langues, mais je ne conclurais pas que cela le qualifie de "mise en garde". Il fait le travail. Cela fonctionne simplement différemment. Lisez simplement ce qu'il fait réellement en Python avant de vous plaindre d'obtenir des résultats auxquels vous ne vous attendiez pas.
TheAtomicOption
3
Quelle est la différence entre les deux?
Tiwtiw
65

Un petit exemple héroïque:

class SuperHero(object): #superclass, inherits from default object
    def getName(self):
        raise NotImplementedError #you want to override this on the child classes

class SuperMan(SuperHero): #subclass, inherits from SuperHero
    def getName(self):
        return "Clark Kent"

class SuperManII(SuperHero): #another subclass
    def getName(self):
       return "Clark Kent, Jr."

if __name__ == "__main__":
    sm = SuperMan()
    print sm.getName()
    sm2 = SuperManII()
    print sm2.getName()
ewall
la source
37
class MySubClass(MySuperClass):
    def __init__(self):
        MySuperClass.__init__(self)

        # <the rest of your custom initialization code goes here>

La section sur l'héritage dans la documentation python l'explique plus en détail

Bryan Oakley
la source
5
Vous n'avez besoin de définir cette __init__méthode que si vous souhaitez y ajouter du code, sinon la méthode init originale est utilisée de toute façon (bien que cela vaille la peine d'être mentionné et que ce soit un code parfaitement valide)
dbr
2
Je pense que la question était assez vague pour supposer qu'un code supplémentaire pourrait être ajouté. Mieux vaut fournir trop d'informations que pas assez et se retrouver avec une autre question lorsque l'OP l'implémente. :)
Matt Dewey
15
class Class1(object):
    pass

class Class2(Class1):
    pass

Class2 est une sous-classe de Class1

workmad3
la source
Cool. C'est ce que je cherchais en fait, c'est-à-dire une sous-classe sans extension / remplacement du super.
BuvinJ
9

Dans les réponses ci-dessus, le superest initialisé sans aucun argument (mot-clé). Cependant, vous aimeriez souvent faire cela, ainsi que transmettre vos propres arguments «personnalisés». Voici un exemple qui illustre ce cas d'utilisation:

class SortedList(list):
    def __init__(self, *args, reverse=False, **kwargs):
        super().__init__(*args, **kwargs)       # Initialize the super class
        self.reverse = reverse
        self.sort(reverse=self.reverse)         # Do additional things with the custom keyword arguments

Il s'agit d'une sous-classe listdont, une fois initialisée, se trie immédiatement dans la direction spécifiée par l' reverseargument mot - clé, comme l'illustrent les tests suivants:

import pytest

def test_1():
    assert SortedList([5, 2, 3]) == [2, 3, 5]

def test_2():
    SortedList([5, 2, 3], reverse=True) == [5, 3, 2]

def test_3():
    with pytest.raises(TypeError):
        sorted_list = SortedList([5, 2, 3], True)   # This doesn't work because 'reverse' must be passed as a keyword argument

if __name__ == "__main__":
    pytest.main([__file__])

Grâce à la transmission de *argsà super, la liste peut être initialisée et remplie d'éléments au lieu d'être uniquement vide. (Notez qu'il reverses'agit d'un argument de mot-clé uniquement conformément à PEP 3102 ).

Kurt Peek
la source
4

Il existe un autre moyen de créer dynamiquement des sous-classes en python avec une fonction type():

SubClass = type('SubClass', (BaseClass,), {'set_x': set_x})  # Methods can be set, including __init__()

Vous souhaitez généralement utiliser cette méthode lorsque vous travaillez avec des métaclasses. Lorsque vous souhaitez effectuer des automatisations de niveau inférieur, cela modifie la façon dont python crée une classe. Vous n'aurez probablement jamais besoin de le faire de cette manière, mais lorsque vous le ferez, vous saurez déjà ce que vous faites.

Pol
la source
3
class Subclass (SuperClass):
      # Subclass stuff here
Wernesey
la source
2
class Mammal(object): 
#mammal stuff

class Dog(Mammal): 
#doggie stuff
Chris Ballance
la source
1
class BankAccount:

  def __init__(self, balance=0):
    self.balance = int(balance)

  def checkBalance(self): ## Checking opening balance....
    return self.balance

  def deposit(self, deposit_amount=1000): ## takes in cash deposit amount and updates the balance accordingly.
    self.deposit_amount = deposit_amount
    self.balance += deposit_amount
    return self.balance

  def withdraw(self, withdraw_amount=500): ## takes in cash withdrawal amount and updates the balance accordingly
    if self.balance < withdraw_amount: ## if amount is greater than balance return `"invalid transaction"`
        return 'invalid transaction'
    else:
      self.balance -= withdraw_amount
      return self.balance


class MinimumBalanceAccount(BankAccount): #subclass MinimumBalanceAccount of the BankAccount class

    def __init__(self,balance=0, minimum_balance=500):
        BankAccount.__init__(self, balance=0)
        self.minimum_balance = minimum_balance
        self.balance = balance - minimum_balance
        #print "Subclass MinimumBalanceAccount of the BankAccount class created!"

    def MinimumBalance(self):
        return self.minimum_balance

c = BankAccount()
print(c.deposit(50))
print(c.withdraw(10))

b = MinimumBalanceAccount(100, 50)
print(b.deposit(50))
print(b.withdraw(10))
print(b.MinimumBalance())
Antiomique
la source
5
Cette réponse serait plus utile si vous
incluiez
4
Bien que ce code puisse aider à résoudre le problème, il n'explique pas pourquoi et / ou comment il répond à la question. Fournir ce contexte supplémentaire améliorerait considérablement sa valeur éducative à long terme. Veuillez modifier votre réponse pour ajouter des explications, y compris les limites et les hypothèses applicables.
Toby Speight
2
Bien que cet extrait de code puisse résoudre la question, inclure une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code.
andreas
0

Le sous-classement en Python se fait comme suit:

class WindowElement:
    def print(self):
        pass

class Button(WindowElement):
    def print(self):
        pass

Voici un tutoriel sur Python qui contient également des classes et des sous-classes.

démister
la source