134 votes

Extension de Python avec - utilisation de super() Python 3 vs Python 2

À l'origine, je voulais demander cette question mais je me suis rendu compte qu'on y avait déjà pensé auparavant...

En cherchant sur Google, j'ai trouvé cet exemple de extension de configparser . Ce qui suit fonctionne avec Python 3 :

$ python3
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2
>>> from configparser import  SafeConfigParser
>>> class AmritaConfigParser(SafeConfigParser):
...     def __init__(self):
...         super().__init__()
... 
>>> cfg = AmritaConfigParser()

Mais pas avec Python 2 :

>>> class AmritaConfigParser(SafeConfigParser):
...       def __init__(self):
...           super(SafeConfigParser).init()
... 
>>> cfg = AmritaConfigParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: must be type, not classob

Ensuite, j'ai lu un peu sur les styles Python New Class et Old Class (par ex. aquí . Et maintenant, je me demande ce que je peux faire :

class MyConfigParser(ConfigParser.ConfigParser):
      def Write(self, fp):
          """override the module's original write funcition"""
          ....
      def MyWrite(self, fp):
          """Define new function and inherit all others"""

Mais ne devrais-je pas appeler init ? Est-ce que c'est l'équivalent dans Python 2 :

 class AmritaConfigParser(ConfigParser.SafeConfigParser):
    #def __init__(self):
    #    super().__init__() # Python3 syntax, or rather, new style class syntax ...
    #
    # is this the equivalent of the above ? 
    def __init__(self):
        ConfigParser.SafeConfigParser.__init__(self)

198voto

mata Points 22446
  • super() (sans arguments) a été introduite dans Python 3 (en même temps que __class__ ) :

    super() -> same as super(__class__, self)

    ce serait donc l'équivalent de Python 2 pour les classes de type nouveau :

    super(CurrentClass, self)
  • pour les classes à l'ancienne que vous pouvez toujours utiliser :

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)

64voto

yak Points 3938

Dans le cas d'un héritage unique (lorsque vous sous-classez une seule classe), votre nouvelle classe hérite des méthodes de la classe de base. Cela inclut les méthodes de la classe de base. __init__ . Ainsi, si vous ne la définissez pas dans votre classe, vous obtiendrez celle de la base.

Les choses commencent à se compliquer si l'on introduit l'héritage multiple (sous-classer plus d'une classe à la fois). En effet, si plus d'une classe de base possède des propriétés __init__ votre classe n'héritera que de la première.

Dans ce cas, il est préférable d'utiliser super si vous le pouvez, je vous expliquerai pourquoi. Mais ce n'est pas toujours le cas. Le problème est que toutes vos classes de base doivent également l'utiliser (et leurs classes de base également - l'arbre entier).

Si c'est le cas, cela fonctionnera aussi correctement (en Python 3 mais vous pourriez le retravailler en Python 2 -- il a aussi super ) :

class A:
    def __init__(self):
        print('A')
        super().__init__()

class B:
    def __init__(self):
        print('B')
        super().__init__()

class C(A, B):
    pass

C()
#prints:
#A
#B

Remarquez que les deux classes de base utilisent super même s'ils n'ont pas de classes de base propres.

Ce qu'il faut faire super est d'appeler la méthode de la classe suivante dans l'ordre de résolution des méthodes (MRO). L'ordre de résolution des méthodes pour C est : (C, A, B, object) . Vous pouvez imprimer C.__mro__ pour le voir.

Ainsi, C hérite __init__ de A y super en A.__init__ appels B.__init__ ( B suit A dans MRO).

Ainsi, en ne faisant rien en C Vous finissez donc par appeler les deux, ce qui est souhaitable.

Si vous n'utilisiez pas super vous hériteriez en fin de compte A.__init__ (comme précédemment), mais cette fois-ci, il n'y a rien qui puisse appeler la fonction B.__init__ pour vous.

class A:
    def __init__(self):
        print('A')

class B:
    def __init__(self):
        print('B')

class C(A, B):
    pass

C()
#prints:
#A

Pour y remédier, vous devez définir C.__init__ :

class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)

Le problème, c'est que dans les arbres de MI plus compliqués, __init__ de certaines classes peuvent être appelées plusieurs fois, alors que super/MRO garantissent qu'elles ne sont appelées qu'une seule fois.

31voto

wuliang Points 319

En bref, ils sont équivalents. Faisons un peu d'histoire :

(1) Dans un premier temps, la fonction se présente comme suit.

    class MySubClass(MySuperClass):
        def __init__(self):
            MySuperClass.__init__(self)

(2) rendre le code plus abstrait (et plus portable). Une méthode courante pour obtenir la Super-Classe est inventée comme suit :

    super(<class>, <instance>)

Et la fonction d'init peut l'être :

    class MySubClassBetter(MySuperClass):
        def __init__(self):
            super(MySubClassBetter, self).__init__()

Cependant, le fait d'exiger le passage explicite de la classe et de l'instance enfreint quelque peu la règle DRY (Don't Repeat Yourself).

(3) dans V3. Elle est plus intelligente,

    super()

suffit dans la plupart des cas. Vous pouvez vous référer à http://www.python.org/dev/peps/pep-3135/

24voto

Jonathan Mugan Points 423

Juste pour avoir un exemple simple et complet pour Python 3, que la plupart des gens semblent utiliser maintenant.

class MySuper(object):
    def __init__(self,a):
        self.a = a

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)

donne

42
chickenman

4voto

SeasonalShot Points 724

Une autre implémentation de python3 qui implique l'utilisation de classes abstraites avec super(). Vous devez vous rappeler que

super().__init__(name, 10)

a le même effet que

Person.__init__(self, name, 10)

Le même objet passe donc à la méthode init de la superclasse et les attributs sont ajoutés à l'objet qui l'a appelée. D'où super() est traduit en Person et si l'on inclut le self caché, on obtient le fragment de code ci-dessus.

from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
    name = ""
    age = 0

    def __init__(self, personName, personAge):
        self.name = personName
        self.age = personAge

    @abstractmethod
    def showName(self):
        pass

    @abstractmethod
    def showAge(self):
        pass

class Man(Person):

    def __init__(self, name, height):
        self.height = height
        # Person.__init__(self, name, 10)
        super().__init__(name, 10)  # same as Person.__init__(self, name, 10)
        # basically used to call the superclass init . This is used incase you want to call subclass init
        # and then also call superclass's init.
        # Since there's a hidden self in the super's parameters, when it's is called,
        # the superclasses attributes are a part of the same object that was sent out in the super() method

    def showIdentity(self):
        return self.name, self.age, self.height

    def showName(self):
        pass

    def showAge(self):
        pass

a = Man("piyush", "179")
print(a.showIdentity())

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X