Toutes les classes Python devraient-elles étendre l'objet?

129

J'ai constaté que les deux travaux suivants:

class Foo():
    def a(self):
        print "hello"

class Foo(object):
    def a(self):
        print "hello"

Toutes les classes Python devraient-elles étendre l'objet? Y a-t-il des problèmes potentiels avec le fait de ne pas étendre l'objet?

Kara
la source
2
Y a-t-il une différence entre class Foo():et class Foo:? Comme je l'observe, les deux fonctionnent en Python 3.
Wolf
Il est bien répondu à cette question: stackoverflow.com/questions/4015417/…
nngeek

Réponses:

117

En Python 2, ne pas hériter de objectcréera une classe à l'ancienne, qui, entre autres effets, typedonne des résultats différents:

>>> class Foo: pass
... 
>>> type(Foo())
<type 'instance'>

contre.

>>> class Bar(object): pass
... 
>>> type(Bar())
<class '__main__.Bar'>

De plus, les règles pour l'héritage multiple sont différentes d'une manière que je n'essaierai même pas de résumer ici. Toute la bonne documentation que j'ai vue sur MI décrit des classes de style nouveau.

Enfin, les classes à l'ancienne ont disparu dans Python 3 et l'héritage de objectest devenu implicite. Donc, préférez toujours les nouvelles classes de style à moins que vous n'ayez besoin d'une compatibilité descendante avec l'ancien logiciel.

Fred Foo
la source
68

Dans Python 3, les classes s'étendent objectimplicitement, que vous le disiez vous-même ou non.

Dans Python 2, il existe des classes de style ancien et nouveau . Pour signaler qu'une classe est de nouveau style, vous devez hériter explicitement de object. Sinon, l'implémentation à l'ancienne est utilisée.

Vous voulez généralement une classe de style nouveau. Hériter de objectexplicitement. Notez que cela s'applique également au code Python 3 qui vise à être compatible avec Python 2.

slezica
la source
Oui, la différence que Free Foo a soulignée , a disparu, BTW: les parenthèses vides sont-elles facultatives?
Wolf le
4
Il y a beaucoup de code python 3 qui utilise foo (object) :. N'est-ce donc qu'une convention?
RFV5s
2
@RFVenter Il peut s'agir d'un code censé s'exécuter à la fois sous Python 2 et 3, auquel cas vous devez sous-classer l'objet explicitement afin que la classe se comporte en grande partie de la même manière sous Python 2.
blubberdiblub
@blubberdiblub C'est ce que je soupçonnais MAIS notre projet tourne exclusivement sur python 3.5 virtualenv. Je pense que le code doit avoir été copié à partir d'un projet python 2.
RFV5s
@RFVenter yup, cela peut être une autre explication. Et bien sûr, si c'est Python 3.x seulement maintenant, c'est bien de se débarrasser des références d'objet.
blubberdiblub
17

En python 3, vous pouvez créer une classe de trois manières différentes et en interne, elles sont toutes égales (voir exemples). Peu importe la façon dont vous créez une classe, toutes les classes de python 3 héritent d'une classe spéciale appelée object . L' objet de classe est une classe fondamentale en python et fournit de nombreuses fonctionnalités telles que les méthodes à double soulignement, les descripteurs, la méthode super (), la méthode property (), etc.

Exemple 1.

class MyClass:
 pass

Exemple 2.

class MyClass():
 pass

Exemple 3.

class MyClass(object):
  pass
N Randhawa
la source
1
Ce n'est pas strictement vrai ... stackoverflow.com/questions/1238606
Philip Adler
Je ne suis pas sûr de vous suivre. Et oui, probablement pas pertinent pour la plupart des gens jusqu'à ce que ce soit pertinent.
Philip Adler
@PhilipAdler Il est généralement supposé que cela objectfait référence à intégré object. Si nous devons prendre en compte le fait que n'importe quel identifiant intégré de CPython peut être remplacé, nous pourrions à peine faire une affirmation sur le modèle de données. Peut-on sérieusement soutenir que strn'accepte pas toujours une chaîne comme argument parce qu'on pourrait l'assigner builtins.str = None?
Nuno André
Je continue de voir cette affirmation selon laquelle c'est "largement supposé", et j'accepte que c'est une hypothèse que chaque implémentation actuelle fait (ce n'est pas une exigence du langage), ce n'est pas mon expérience que la majorité des programmeurs python je se sont rencontrés, supposons cela, le savent ou même l’ont envisagé. Indépendamment de cela, l'affirmation selon laquelle elle est communément supposée, même si elle est vraie, n'invalide pas mon affirmation selon laquelle l'équivalence n'est pas strictement vraie.
Philip Adler
1

Oui, toutes les classes Python devraient étendre (ou plutôt une sous-classe, c'est Python ici) objet. Bien que normalement aucun problème sérieux ne se produise, dans certains cas (comme avec plusieurs arbres d'héritage), cela sera important. Cela garantit également une meilleure compatibilité avec Python 3.

pydsigner
la source
1
exactement, techniquement, si vous ne le faites pas, vous obtiendrez une classe classique, mais il n'y a pas de réels avantages à cela et elle n'est de toute façon pas prise en charge par python 3
max k.
Je suis curieux de savoir pourquoi cela améliore la compatibilité avec python3. À ma connaissance, python3 le fera étendre l'objet automatiquement même si vous ne le spécifiez pas, non?
Paul Lo
2
@PaulLo Oui, mais si vous héritez explicitement d'un objet, vous obtiendrez le même comportement (nouveau style) sur Python 2 et Python 3. Il ne s'agit pas de changer le fonctionnement de Python 3, il s'agit d'utiliser forward -compatibilité sur Python 2.
pydsigner
Cette suggestion n'a pas l'air très élégante, mais si vous vous adressez à Python2 et Python3, elle semble efficace. Mais quelle est sa pertinence dans la pratique?
Wolf le
@Wolf Cela dépend de ce que vous faites. Si vous avez des arbres d'héritage complexes, cela compte beaucoup. Si vous voulez que votre classe soit un descripteur, vous devez utiliser un nouveau style. Vous pouvez suivre les liens de stackoverflow.com/questions/54867/… si vous souhaitez des informations plus détaillées.
pydsigner
1

Comme d'autres réponses l'ont couvert, l'héritage Python 3 de l'objet est implicite. Mais ils n'indiquent pas ce que vous devez faire et ce que sont les conventions.

Les exemples de documentation Python 3 utilisent tous le style suivant qui est une convention, je vous suggère donc de suivre ceci pour tout code futur dans Python 3.

class Foo:
    pass

Source: https://docs.python.org/3/tutorial/classes.html#class-objects

Exemple de devis:

Les objets de classe prennent en charge deux types d'opérations: les références d'attributs et l'instanciation.

Les références d'attribut utilisent la syntaxe standard utilisée pour toutes les références d'attribut en Python: obj.name. Les noms d'attribut valides sont tous les noms qui se trouvaient dans l'espace de noms de la classe lorsque l'objet de classe a été créé. Donc, si la définition de classe ressemblait à ceci:

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

Une autre citation:

De manière générale, les variables d'instance sont destinées aux données propres à chaque instance et les variables de classe sont destinées aux attributs et méthodes partagés par toutes les instances de la classe:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance
jmoz
la source
0

en python3, il n'y a pas de différence, mais en python2, ne pas étendre objectvous donne des classes à l'ancienne; vous souhaitez utiliser une classe de style nouveau sur une classe de style ancien.

Thkang
la source
2
Cette réponse est raisonnable, mais d'autres répondeurs y sont arrivés plus rapidement et / ou plus en détail; cette réponse n'ajoute aucune valeur à la page telle qu'elle est.
Mark Amery