La classe Python eredita l'oggetto


1245

C'è qualche motivo per cui una dichiarazione di classe erediti object?

Ho appena trovato un codice che lo fa e non riesco a trovare una buona ragione per cui.

class MyClass(object):
    # class code follows...

2
Questo crea una nuova classe di stile .
SLaks

116
La risposta a questa domanda (sebbene semplice) è piuttosto difficile da trovare. Googling cose come "python object base class" o simili si presentano con pagine e pagine di tutorial sulla programmazione orientata agli oggetti. La votazione perché questo è il primo link che mi ha portato ai termini di ricerca "oggetti in pitone vecchi e nuovi"
vastlysuperiorman,

Risposte:


765

C'è qualche motivo per cui una dichiarazione di classe erediti object?

In Python 3, a parte la compatibilità tra Python 2 e 3, nessun motivo . In Python 2, molte ragioni .


Storia di Python 2.x:

In Python 2.x (dalla versione 2.2 in poi) ci sono due stili di classi a seconda della presenza o assenza di objectcome classe base:

  1. Classi di stile "classico" : non hanno objectcome classe di base:

    >>> class ClassicSpam:      # no base class
    ...     pass
    >>> ClassicSpam.__bases__
    ()
  2. "nuove" classi di stile : hanno, direttamente o indirettamente (ad esempio ereditare da un tipo incorporato ), objectcome classe di 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'>,)

Senza dubbio, quando scrivi una classe ti consigliamo sempre di seguire lezioni di nuovo stile. I vantaggi di farlo sono numerosi, per elencarne alcuni:

  • Supporto per descrittori . In particolare, i seguenti costrutti sono resi possibili con i descrittori:

    1. classmethod: Un metodo che riceve la classe come argomento implicito anziché l'istanza.
    2. staticmethod: Un metodo che non riceve l'argomento implicito selfcome primo argomento.
    3. proprietà con property: Crea funzioni per gestire l'ottenimento, l'impostazione e l'eliminazione di un attributo.
    4. __slots__: Salva i consumi di memoria di una classe e consente anche un accesso più rapido agli attributi. Certo, impone limiti .
  • Il __new__metodo statico: consente di personalizzare la modalità di creazione delle nuove istanze di classe.

  • Ordine di risoluzione del metodo (MRO) : in quale ordine verranno ricercate le classi base di una classe quando si cerca di risolvere quale metodo chiamare.

  • Relativo a MRO, superchiamate . Vedi anche, super()considerato super.

Se non erediti object, dimentica questi. Una descrizione più esaustiva dei punti elenco precedenti insieme ad altri vantaggi di "nuove" classi di stile è disponibile qui .

Uno degli svantaggi delle classi di nuovo stile è che la classe stessa richiede più memoria. A meno che tu non stia creando molti oggetti di classe, dubito che questo sarebbe un problema ed è un affondamento negativo in un mare di aspetti positivi.


Storia di Python 3.x:

In Python 3, le cose sono semplificate. Esistono solo classi di nuovo stile (definite chiaramente come classi), quindi l'unica differenza nell'aggiunta objectè la necessità di digitare altri 8 caratteri. Questo:

class ClassicSpam:
    pass

è completamente equivalente (a parte il loro nome :-) a questo:

class NewSpam(object):
     pass

e a questo:

class Spam():
    pass

Tutti hanno objectnel loro __bases__.

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

Quindi cosa dovresti fare?

In Python 2: eredita sempre in modo objectesplicito . Ottieni i vantaggi.

In Python 3: eredita da objectse stai scrivendo codice che cerca di essere agnostico in Python, cioè deve funzionare sia in Python 2 che in Python 3. Altrimenti, non fa davvero differenza, poiché Python lo inserisce per te dietro le quinte.


"a seconda della presenza o assenza di un tipo incorporato come classe base" => in realtà non si tratta di "assenza o presenza di un tipo incorporato come classe base", ma se la classe eredita - direttamente o indirettamente - da object. IIRC ci fu un momento in cui non tutti i tipi incorporati venivano portati su classi di nuovo stile.
bruno desthuilliers,

@brunodesthuilliers La mia impressione era che tutti i tipi predefiniti ereditassero object. Ho un Python 2.2.3 in giro e dopo un rapido controllo non sono riuscito a trovare un colpevole, ma riformulerò la risposta in seguito per renderlo più chiaro. Sarei interessato se potessi trovare un esempio, però, la mia curiosità è accesa.
Dimitris Fasarakis Hilliard,

In tutta onestà (cfr. "IIRC" nel mio commento precedente) non sono sicuro al 101% su questo punto (se tutti i tipi predefiniti fossero già convertiti in classi di nuovo stile quando sono state introdotte classi di nuovo stile) - Potrei semplicemente essere chiaro sbagliato, o questo potrebbe aver riguardato solo alcuni dei tipi di lib standard (ma non integrati). Ma penso che dovrebbe essere meglio chiarire che ciò che rende una classe di nuovo stile sta objectnelle sue basi.
bruno desthuilliers,

7
stackoverflow troppo male fa solo upvote = upvote + 1 per queste risposte un po ', vorrei poter fare upvote + = N
PirateApp

1
staticmethode classmethodfunziona perfettamente anche su lezioni di vecchio stile. propertysorta funziona per la lettura su classi di vecchio stile, non riesce a intercettare le scritture (quindi se si assegna al nome, l'istanza ottiene un attributo del nome dato che ombreggia la proprietà). Si noti inoltre che __slots__il miglioramento della velocità di accesso agli attributi consiste principalmente nell'annullare la perdita che comporta l'accesso agli attributi di classe di nuovo stile, quindi non è realmente un punto di forza delle classi di nuovo stile (i risparmi di memoria sono comunque un punto di forza).
ShadowRanger

540

Python 3

  • class MyClass(object): = Classe di nuovo stile
  • class MyClass:= Classe new-style (eredita implicitamente da object)

Python 2

  • class MyClass(object): = Classe di nuovo stile
  • class MyClass:= CLASSE VECCHIO STILE

Spiegazione :

Quando si definiscono le classi di base in Python 3.x, è possibile eliminare la objectdalla definizione. Tuttavia, questo può aprire la porta a un problema seriamente difficile da rintracciare ...

Python ha introdotto classi di nuovo stile in Python 2.2, e ormai le classi di vecchio stile sono davvero piuttosto vecchie. La discussione sulle classi di vecchio stile è sepolta nei documenti 2.x e inesistente nei documenti 3.x.

Il problema è, la sintassi per le classi vecchio stile in Python 2.x è la stessa della sintassi alternativa per classi di nuovo stile in Python 3.x . Python 2.x è ancora molto usato (ad esempio GAE, Web2Py) e qualsiasi codice (o codificatore) che porta inconsapevolmente definizioni di classe in stile 3.x nel codice 2.x finirà con alcuni oggetti di base seriamente obsoleti. E poiché le lezioni di vecchio stile non sono sul radar di nessuno, probabilmente non sapranno cosa li ha colpiti.

Quindi basta spiegarlo a lungo e salvare alcune lacrime dagli sviluppatori 2.x.


13
"Quando si definiscono le classi di base in Python 3.x, è possibile eliminare l'oggetto dalla definizione. Tuttavia, questo può aprire la porta a un problema seriamente difficile da tracciare ..." A quali problemi si fa riferimento?
Aidis,

6
@Aidis: Penso che intendano dire che il codice che gira su Py2 e Py3 andrebbe bene su Py3, ma sarebbe rotto su Py2 se si basava su nuove funzionalità di classe di stile. Personalmente, se sto scrivendo un codice del genere, ometto l'ereditarietà esplicita e lo metto __metaclass__ = typein cima al modulo (dopo la from __future__ import absolute_import, division, print_functionriga :-)); è un hack di compatibilità in Py2 che rende tutte le classi successivamente definite nel modulo di nuovo stile di default, e in Py3, è completamente ignorato (solo una variabile globale casuale attorno), quindi è innocuo.
ShadowRanger

400

Sì, questo è un oggetto "nuovo stile". Era una funzionalità introdotta in python2.2.

Oggetti nuovi di stile hanno un modello diverso oggetto agli oggetti classici, e alcune cose non funzioneranno correttamente con oggetti in stile antico, per esempio, super(), @propertye descrittori. Vedi questo articolo per una buona descrizione di cosa sia una nuova classe di stile.

Collegamento SO per una descrizione delle differenze: Qual è la differenza tra vecchio stile e nuove classi di stile in Python?


110
+1 questo. Si noti che le classi vecchio stile sono state eliminate in Python 3, quindi è necessario ereditare solo objectin Python 2.

9
Questa non è una vera risposta. Dà solo riferimento ad altri articoli. Penso che la risposta di Yarin dovrebbe essere accettata come risposta a questa domanda.
alwbtc,

2
@alwbtc: anche questa risposta ha qualcosa di nuovo. Ad esempio la menzione di "super ()" mi ha portato ad un altro importante [qui] ( stackoverflow.com/questions/576169/… ).
ViFI,

34

Storia da Learn Python nel modo più duro :

La versione originale di Python di una classe è stata interrotta in molti modi seri. Quando fu riconosciuto che questo errore era già troppo tardi, e dovettero sostenerlo. Per risolvere il problema, avevano bisogno di uno stile di "nuova classe" in modo che le "vecchie classi" continuassero a funzionare ma è possibile utilizzare la nuova versione più corretta.

Decisero che avrebbero usato una parola "oggetto", in minuscolo, per essere la "classe" da cui erediti per creare una classe. È fonte di confusione, ma una classe eredita dalla classe denominata "oggetto" per creare una classe ma non è un oggetto in realtà è una classe, ma non dimenticare di ereditare dall'oggetto.

Inoltre, solo per farti sapere qual è la differenza tra le classi di nuovo stile e le classi di vecchio stile, è che le classi di nuovo stile ereditano sempre dalla objectclasse o da un'altra classe ereditata da object:

class NewStyle(object):
    pass

Un altro esempio è:

class AnotherExampleOfNewStyle(NewStyle):
    pass

Mentre una classe base vecchio stile assomiglia a questo:

class OldStyle():
    pass

E una classe per bambini vecchio stile assomiglia a questo:

class OldStyleSubclass(OldStyle):
    pass

Puoi vedere che una classe base Old Style non eredita da nessun'altra classe, tuttavia, le classi Old Style possono, ovviamente, ereditare l'una dall'altra. L'ereditarietà da oggetto garantisce che determinate funzionalità siano disponibili in ogni classe Python. Nuove classi di stile sono state introdotte in Python 2.2


8
Chiamare la classe root objectnon è poi così confuso, e in effetti è piuttosto standard. Smalltalk ha una classe radice denominata Objecte una metaclasse radice denominata Class. Perché? Perché, così come Dogè una classe per i cani, Objectè una classe per gli oggetti ed Classè una classe per le classi. Java, C #, ObjC, Ruby e la maggior parte dei linguaggi OO basati su classi che le persone usano oggi che hanno una classe radice usano alcune varianti Objectcome nome, non solo Python.
abarnert,

30

Sì, è storico . Senza di essa, crea una classe vecchio stile.

Se lo usi type()su un oggetto vecchio stile, ottieni semplicemente "istanza". Su un oggetto di nuovo stile ottieni la sua classe.


Inoltre, se usi type()una classe vecchio stile, otterrai "classobj" invece di "tipo".
Joel Sjögren,

7

La sintassi dell'istruzione di creazione della classe:

class <ClassName>(superclass):
    #code follows

In assenza di altre superclassi da cui si desidera ereditare in modo specifico, superclassdovrebbe essere sempre object, che è la radice di tutte le classi in Python.

objectè tecnicamente la radice delle classi "new-style" in Python. Ma le lezioni di nuovo stile oggi sono buone come essere l'unico stile di lezioni.

Ma, se non si usa esplicitamente la parola objectdurante la creazione di classi, come altri hanno già detto, Python 3.x eredita implicitamente dalla objectsuperclasse. Ma credo che esplicito sia sempre meglio di implicito (inferno)

Riferimento

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.