La classe Python hérite de l'objet

1246

Y a-t-il une raison pour qu'une déclaration de classe hérite object?

Je viens de trouver du code qui fait cela et je ne trouve pas de bonne raison.

class MyClass(object):
    # class code follows...
tjvr
la source
2
Cela crée une classe de nouveau style .
SLaks
116
La réponse à cette question (bien que simple) est assez difficile à trouver. Googler des choses comme "classe de base d'objets python" ou similaire propose des pages et des pages de tutoriels sur la programmation orientée objet. Voter parce que c'est le premier lien qui m'a conduit aux termes de recherche "objets python anciens vs nouveaux styles"
vastlysuperiorman

Réponses:

765

Y a-t-il une raison pour qu'une déclaration de classe hérite object?

En Python 3, mis à part la compatibilité entre Python 2 et 3, aucune raison . En Python 2, plusieurs raisons .


Histoire de Python 2.x:

Dans Python 2.x (à partir de la version 2.2), il existe deux styles de classes en fonction de la présence ou de l'absence de objectclasse de base:

  1. classes de style "classique" : elles n'ont pas objectcomme classe de base:

    >>> class ClassicSpam:      # no base class
    ...     pass
    >>> ClassicSpam.__bases__
    ()
  2. "nouvelles" classes de style : elles ont, directement ou indirectement (par exemple hériter d'un type intégré ), objectcomme classe de base:

    >>> class NewSpam(object):           # directly inherit from object
    ...    pass
    >>> NewSpam.__bases__
    (<type 'object'>,)
    >>> class IntSpam(int):              # indirectly inherit from object...
    ...    pass
    >>> IntSpam.__bases__
    (<type 'int'>,) 
    >>> IntSpam.__bases__[0].__bases__   # ... because int inherits from object  
    (<type 'object'>,)

Sans aucun doute, lors de l'écriture d'une classe, vous aurez toujours envie d'opter pour des classes de nouveau style. Les avantages de le faire sont nombreux, pour en énumérer certains:

  • Prise en charge des descripteurs . Plus précisément, les constructions suivantes sont rendues possibles avec des descripteurs:

    1. classmethod: Une méthode qui reçoit la classe comme argument implicite au lieu de l'instance.
    2. staticmethod: Une méthode qui ne reçoit pas l'argument implicite self comme premier argument.
    3. propriétés avec property: Créer des fonctions pour gérer l'obtention, la définition et la suppression d'un attribut.
    4. __slots__: Enregistre les consommations de mémoire d'une classe et accélère également l'accès aux attributs. Bien sûr, cela impose des limitations .
  • La __new__méthode statique: vous permet de personnaliser la façon dont les nouvelles instances de classe sont créées.

  • Ordre de résolution des méthodes (MRO) : dans quel ordre les classes de base d'une classe seront recherchées lors de la tentative de résolution de la méthode à appeler.

  • Lié au MRO, aux superappels . Voir aussi, super()considéré comme super.

Si vous n'héritez pas object, oubliez-les. Une description plus exhaustive des puces précédentes ainsi que d'autres avantages des "nouvelles" classes de style peuvent être trouvées ici .

L'un des inconvénients des classes de nouveau style est que la classe elle-même est plus gourmande en mémoire. À moins que vous ne créiez de nombreux objets de classe, je doute que ce soit un problème et que ce soit un naufrage négatif dans une mer de points positifs.


Histoire de Python 3.x:

En Python 3, les choses sont simplifiées. Seules les classes de nouveau style existent (appelées clairement classes) donc la seule différence dans l'ajout objectest de vous obliger à taper 8 caractères supplémentaires. Cette:

class ClassicSpam:
    pass

est complètement équivalent (à part leur nom :-) à ceci:

class NewSpam(object):
     pass

et à cela:

class Spam():
    pass

Tous ont objecten leur __bases__.

>>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]
[True, True, True]

Alors, que devrais-tu faire?

En Python 2: toujours hérité de objectexplicitement . Obtenez les avantages.

En Python 3: héritez de objectsi vous écrivez du code qui essaie d'être agnostique Python, c'est-à-dire qu'il doit fonctionner à la fois en Python 2 et en Python 3. Sinon, cela ne fait vraiment aucune différence puisque Python l'insère pour vous Dans les coulisses.

Dimitris Fasarakis Hilliard
la source
"selon la présence ou l'absence d'un type intégré en tant que classe de base" => en réalité, il ne s'agit pas "d'absence ou de présence d'un type intégré en tant que classe de base", mais si la classe hérite - directement ou indirectement - de object. IIRC il y a eu un moment où tous les types intégrés n'étaient pas encore portés vers des classes de nouveau style.
bruno desthuilliers
@brunodesthuilliers Mon impression était que tous les types intégrés héritaient de object. J'ai un Python 2.2.3 autour et après une vérification rapide, je n'ai pas trouvé de délinquant, mais je reformulerai la réponse plus tard pour que ce soit plus clair. Serait intéressé si vous pouviez trouver un exemple, ma curiosité est piquée.
Dimitris Fasarakis Hilliard
En toute honnêteté (cf. "IIRC" dans mon commentaire précédent), je ne suis pas sûr à 101% de ce point (si tous les types intégrés ont déjà été convertis en classes de nouveau style lorsque les classes de nouveau style ont été introduites) - je pourrais être simple mal, ou cela pourrait ne concerner que certains types de lib standard (mais pas intégré). Mais pourtant, je pense qu'il devrait être préférable de clarifier ce qui fait qu'une classe de nouveau style objecta ses bases.
bruno desthuilliers
7
trop mauvais stackoverflow ne fait que upvote = upvote + 1 pour ces réponses un peu, j'aimerais pouvoir faire upvote + = N
PirateApp
1
staticmethodet classmethodfonctionne très bien même sur les classes à l'ancienne. propertysorta fonctionne pour la lecture sur les classes à l'ancienne, il échoue tout simplement à intercepter les écritures (donc si vous attribuez au nom, l'instance gagne un attribut du nom donné qui masque la propriété). Notez également que __slots__l'amélioration de la vitesse d'accès aux attributs consiste principalement à annuler la perte subie par l'accès aux attributs de classe de nouveau style, donc ce n'est pas vraiment un argument de vente des classes de nouveau style (les économies de mémoire sont un argument de vente cependant).
ShadowRanger
540

Python 3

  • class MyClass(object): = Classe de nouveau style
  • class MyClass:= Classe de nouveau style (hérite implicitement de object)

Python 2

  • class MyClass(object): = Classe de nouveau style
  • class MyClass:= CLASSE ANCIENNE

Explication :

Lors de la définition des classes de base dans Python 3.x, vous êtes autorisé à supprimer la objectde la définition. Cependant, cela peut ouvrir la porte à un problème très difficile à suivre…

Python a réintroduit des classes de nouveau style dans Python 2.2, et maintenant les classes de style ancien sont vraiment assez anciennes. La discussion sur les classes à l'ancienne est enterrée dans les documents 2.x et inexistante dans les documents 3.x.

Le problème est, la syntaxe pour les classes de style ancien en Python 2.x est la même que la syntaxe alternative pour les classes de nouveau style 3.x Python . Python 2.x est encore très largement utilisé (par exemple GAE, Web2Py), et tout code (ou codeur) apportant involontairement des définitions de classe de style 3.x dans le code 2.x va se retrouver avec des objets de base sérieusement obsolètes. Et parce que les cours à l'ancienne ne sont sur le radar de personne, ils ne sauront probablement pas ce qui les a frappés.

Il suffit donc de l'épeler sur le long chemin et de sauver un développeur 2.x les larmes.

Yarin
la source
13
"Lors de la définition des classes de base dans Python 3.x, vous êtes autorisé à supprimer l'objet de la définition. Cependant, cela peut ouvrir la porte à un problème très difficile à suivre ..." À quels problèmes faites-vous référence?
Aidis
6
@Aidis: Je pense qu'ils signifient que le code qui s'exécute à la fois sur Py2 et Py3 conviendrait à Py3, mais serait rompu à Py2 s'il s'appuie sur des fonctionnalités de classe de nouveau style. Personnellement, si j'écris du code comme ça, j'omet l'héritage explicite et je le mets juste __metaclass__ = typeen haut du module (après la from __future__ import absolute_import, division, print_functionligne :-)); c'est un piratage de compatibilité dans Py2 qui rend toutes les classes définies par la suite dans le module nouveau style par défaut, et dans Py3, il est complètement ignoré (juste une variable globale aléatoire assise), donc c'est inoffensif.
ShadowRanger
400

Oui, c'est un objet "nouveau style". C'était une fonctionnalité introduite dans python2.2.

Les nouveaux objets de style ont un modèle d'objet différent des objets classiques, et certaines choses ne fonctionneront pas correctement avec les objets de style ancien, par exemple super(), @propertyet les descripteurs. Consultez cet article pour une bonne description de ce qu'est une nouvelle classe de style.

Lien SO pour une description des différences: Quelle est la différence entre les classes de style ancien et nouveau en Python?

Jerub
la source
110
+1 Ceci. Notez que les classes à l'ancienne ont disparu en Python 3, vous n'avez donc qu'à hériter de objectPython 2.
9
Ce n'est pas une vraie réponse. ı fait simplement référence à d'autres articles. Je pense que la réponse de Yarin devrait être acceptée comme réponse à cette question.
alwbtc
2
@alwbtc: Cette réponse a aussi quelque chose de nouveau. Par exemple, la mention de "super ()" m'a conduit à un autre important [ici] ( stackoverflow.com/questions/576169/… ).
ViFI
34

L'histoire de Learn Python the Hard Way :

L'interprétation originale d'une classe par Python a été interrompue de nombreuses manières graves. Au moment où cette faute a été reconnue, il était déjà trop tard et ils ont dû la soutenir. Afin de résoudre le problème, ils avaient besoin d'un style de "nouvelle classe" pour que les "anciennes classes" continuent de fonctionner mais vous pouvez utiliser la nouvelle version plus correcte.

Ils ont décidé qu'ils utiliseraient un mot "objet", en minuscule, pour être la "classe" dont vous héritez pour créer une classe. C'est déroutant, mais une classe hérite de la classe nommée "objet" pour en faire une classe mais ce n'est pas vraiment un objet c'est une classe, mais n'oubliez pas d'hériter de l'objet.

Aussi pour vous faire savoir quelle est la différence entre les classes de nouveau style et les classes de style ancien, c'est que les classes de nouveau style héritent toujours de la objectclasse ou d'une autre classe qui a hérité de object:

class NewStyle(object):
    pass

Un autre exemple est:

class AnotherExampleOfNewStyle(NewStyle):
    pass

Alors qu'une classe de base à l'ancienne ressemble à ceci:

class OldStyle():
    pass

Et une classe enfant à l'ancienne ressemble à ceci:

class OldStyleSubclass(OldStyle):
    pass

Vous pouvez voir qu'une classe de base Old Style n'hérite d'aucune autre classe, cependant, les classes Old Style peuvent, bien sûr, hériter les unes des autres. L'héritage de l'objet garantit que certaines fonctionnalités sont disponibles dans chaque classe Python. De nouvelles classes de style ont été introduites dans Python 2.2

disp_name
la source
8
Appeler la classe racine objectn'est pas si déroutant, et en fait c'est assez standard. Smalltalk a une classe racine nommée Objectet une métaclasse racine nommée Class. Pourquoi? Parce que, tout comme Dogune classe pour chiens, Objectest une classe pour objets et Classest une classe pour classes. Java, C #, ObjC, Ruby et la plupart des autres langages OO basés sur les classes que les gens utilisent aujourd'hui et qui ont une classe racine utilisent une certaine variation de Objectcomme nom, pas seulement Python.
abarnert
30

Oui, c'est historique . Sans cela, il crée une classe à l'ancienne.

Si vous utilisez type()sur un objet à l'ancienne, vous obtenez simplement "instance". Sur un objet de nouveau style, vous obtenez sa classe.

knitti
la source
De plus, si vous utilisez type()une classe à l'ancienne, vous obtenez "classobj" au lieu de "type".
Joel Sjögren
7

La syntaxe de l'instruction de création de classe:

class <ClassName>(superclass):
    #code follows

En l'absence d'autres superclasses dont vous souhaitez spécifiquement hériter, la superclassdevrait toujours être object, qui est la racine de toutes les classes en Python.

objectest techniquement la racine des classes "new-style" en Python. Mais les classes de nouveau style aujourd'hui sont aussi bonnes que d'être le seul style de classes.

Mais, si vous n'utilisez pas explicitement le mot objectlors de la création de classes, alors comme d'autres l'ont mentionné, Python 3.x hérite implicitement de la objectsuperclasse. Mais je suppose qu'explicite vaut toujours mieux qu'implicite (enfer)

Référence

kmario23
la source