web-dev-qa-db-fra.com

Python étendre avec - en utilisant super () Python 3 vs Python 2

À l’origine, je voulais demander cette question , mais j’ai trouvé que c’était déjà pensé avant….

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 Nouvelle classe contre Ancienne classe (par exemple ici . Et maintenant je me demande, 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 dans Python 2 l'équivalent:

 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)
86
Oz123
  • super() (sans arguments) a été introduit dans Python 3 (avec __class__):

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

    ce serait donc l'équivalent Python 2 pour les classes new-style:

    super(CurrentClass, self)
    
  • pour les classes de style ancien, vous pouvez toujours utiliser:

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

Dans un cas d'héritage unique (lorsque vous ne sous-classez qu'une seule classe), votre nouvelle classe hérite des méthodes de la classe de base. Ceci comprend __init__. Donc, si vous ne le définissez pas dans votre classe, vous obtiendrez celui de la base.

Les choses commencent à être compliquées si vous introduisez l'héritage multiple (sous-classe de plus d'une classe à la fois). En effet, si plusieurs classes de base ont __init__ _, votre classe héritera du premier seulement.

Dans de tels cas, vous devriez vraiment utiliser super si vous le pouvez, je vais expliquer pourquoi. Mais pas toujours. Le problème est que toutes vos classes de base doivent également l'utiliser (et leurs classes de base également - l'arborescence complète).

Si tel est le cas, cela fonctionnera également correctement (dans Python 3 mais vous pouvez le retravailler dans Python 2 - il comporte également 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 comment les deux classes de base utilisent super même si elles ne possèdent pas leurs propres classes de base.

Qu'est-ce que super fait: il appelle la méthode de la classe suivante dans MRO (méthode resolution order). Le MRO pour C est: (C, A, B, object). Vous pouvez imprimer C.__mro__ voir ça.

Donc, C hérite de __init__ de A et super dans A.__init__ appels B.__init__ _ (B suit A dans MRO).

Donc, en ne faisant rien dans C, vous finissez par appeler les deux, ce que vous voulez.

Maintenant, si vous n’utilisiez pas super, vous hériteriez de A.__init__ (comme avant) mais cette fois, rien n’appellerait 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 résoudre ce problème, 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 MI plus complexes, __init__ Les méthodes de certaines classes peuvent être appelées plus d'une fois, alors que Super/MRO garantit qu'elles ne sont appelées qu'une seule fois.

44
yak

En bref, ils sont équivalents. Ayons une vue historique:

(1) au début, la fonction ressemble à ceci.

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

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

    super(<class>, <instance>)

Et la fonction init peut être:

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

Toutefois, nécessitant un passage explicite de la classe et de l'instance, la règle DRY (ne vous répétez pas)) est légèrement annulée.

(3) dans V3. C'est plus intelligent,

    super()

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

22
wuliang

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
20
Jonathan Mugan

Une autre implémentation de python3 qui implique l'utilisation de classes abstraites avec super (). Tu devrais te rappeler que

super () .init (nom, 10)

a le même effet que

Personne .init (self, name, 10)

N'oubliez pas qu'il y a un 'self' caché dans super (). Ainsi, le même objet est transmis à la méthode init de la superclasse et les attributs sont ajoutés à l'objet qui l'a appelé. Par conséquent, super() est traduit en Person, puis si vous incluez le moi caché, vous obtenez le code fragmenté 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())
1
SeasonalShot