Tutte le classi Python dovrebbero estendere l'oggetto?


129

Ho scoperto che entrambi i seguenti lavori:

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

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

Tutte le classi Python dovrebbero estendere l'oggetto? Ci sono potenziali problemi con la non estensione dell'oggetto?


2
C'è una differenza tra class Foo():e class Foo:? Come osservo, entrambi funzionano in Python 3.
Wolf,

E 'ben risolta in questa domanda: stackoverflow.com/questions/4015417/...
nngeek

Risposte:


117

In Python 2, non ereditare da objectcreerà una classe vecchio stile, che, tra gli altri effetti, provoca typerisultati diversi:

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

vs.

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

Anche le regole per l'ereditarietà multipla sono diverse in modi che non proverò nemmeno a riassumere qui. Tutta la buona documentazione che ho visto su MI descrive classi di nuovo stile.

Infine, le classi vecchio stile sono scomparse in Python 3 e l'ereditarietà objectè diventata implicita. Quindi, preferisci sempre nuove classi di stile a meno che tu non abbia bisogno di retrocompatibilità con il vecchio software.


68

In Python 3, le classi si estendono objectimplicitamente, che tu lo dica da solo o no.

In Python 2, ci sono classi vecchio stile e nuovo stile . Per segnalare che una classe è di nuovo stile, devi ereditare esplicitamente da object. In caso contrario, viene utilizzata l'implementazione vecchio stile.

In genere vuoi una lezione di nuovo stile. Eredita da objectesplicitamente. Nota che questo vale anche per il codice Python 3 che mira a essere compatibile con Python 2.


Sì, la differenza ha sottolineato Free Foo , è andata, BTW: le parentesi vuote sono opzionali?
Lupo,

4
C'è un sacco di codice Python 3 che utilizza foo (oggetto) :. È solo una convention allora?
RFV5s

2
@RFVenter Potrebbe essere un codice che dovrebbe essere eseguito con Python 2 e 3, nel qual caso è necessario sottoclassare esplicitamente l'oggetto per far sì che la classe si comporti sostanzialmente allo stesso modo in Python 2.
blubberdiblub

@blubberdiblub Questo è quello che sospettavo MA il nostro progetto è in esecuzione esclusivamente su virtualenv python 3.5. Penso che il codice debba essere stato copiato da un progetto Python 2.
RFV5

@RFVenter sì, potrebbe essere un'altra spiegazione. E, naturalmente, se è Python 3.x solo ora, va bene eliminare i riferimenti agli oggetti.
Blubberdiblub,

17

In Python 3 puoi creare una classe in tre modi diversi e internamente sono tutti uguali (vedi esempi). Non importa come si crea una classe, tutte le classi in Python 3 ereditano da una classe speciale chiamata oggetto . L' oggetto class è una classe fondamentale in Python e offre molte funzionalità come metodi con doppio trattino basso, descrittori, metodo super (), metodo property () ecc.

Esempio 1.

class MyClass:
 pass

Esempio 2

class MyClass():
 pass

Esempio 3

class MyClass(object):
  pass

1
Questo non è strettamente vero ... stackoverflow.com/questions/1238606/…
Philip Adler,

Non sono sicuro di seguirti. E sì, probabilmente non è rilevante per la maggior parte delle persone fino a quando non è rilevante.
Philip Adler,

@PhilipAdler Si presume comunemente che objectfaccia riferimento al built-in object. Se dobbiamo tener conto del fatto che qualsiasi identificatore integrato di CPython può essere sostituito, potremmo a malapena fare qualche affermazione sul modello di dati. Si può seriamente sostenere che strnon si accetta sempre una stringa come argomento perché si potrebbe assegnare builtins.str = None?
Nuno André,

Continuo a vedere questa affermazione che questo è "ampiamente assunto", e accetto che sia un presupposto che ogni implementazione corrente fa (non è un requisito del linguaggio), non è stata la mia esperienza che la maggior parte dei programmatori python I l'ho incontrato, presumilo, o l'hai persino preso in considerazione. Indipendentemente da ciò, l'affermazione che viene comunemente assunta, anche se vera, non invalida la mia affermazione che l'equivalenza non è strettamente vera.
Philip Adler,

1

Sì, tutte le classi Python dovrebbero estendere (o meglio la sottoclasse, qui Python). Sebbene normalmente non si verifichino problemi seri, in alcuni casi (come con più alberi ereditari) questo sarà importante. Ciò garantisce anche una migliore compatibilità con Python 3.


1
esattamente, tecnicamente se non lo farai otterrai una classe classica, ma non ci sono reali vantaggi in questo e non è supportato da Python 3 comunque
max k.

Sono curioso di sapere perché migliora la compatibilità con python3. Per quanto ne so, python3 lo farà estendere l'oggetto automaticamente anche se non lo specifichi, giusto?
Paul Lo,

2
@PaulLo Giusto, ma se erediti esplicitamente dall'oggetto, otterrai lo stesso comportamento (nuovo stile) sia su Python 2 che su Python 3. Non si tratta di cambiare il modo in cui Python 3 funziona, si tratta di usare forward -compatibilità su Python 2.
pydsigner

Questo suggerimento non sembra molto elegante, ma nel caso in cui ti rivolgi a Python2 e Python3, sembra efficace. Ma quanto è rilevante nella pratica?
Lupo,

@Wolf Dipende da cosa stai facendo. Se hai alberi ereditari complessi, conta molto. Se vuoi che la tua classe sia un descrittore, devi usare il nuovo stile. Puoi seguire i link da stackoverflow.com/questions/54867/… se desideri informazioni più approfondite.
pydsigner,

1

Come hanno coperto altre risposte, l'ereditarietà di Python 3 dall'oggetto è implicita. Ma non dichiarano cosa dovresti fare e cos'è la convenzione.

Gli esempi di documentazione di Python 3 usano tutti il ​​seguente stile che è convenzione, quindi ti suggerisco di seguirlo per qualsiasi codice futuro in Python 3.

class Foo:
    pass

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

Citazione di esempio:

Gli oggetti di classe supportano due tipi di operazioni: riferimenti di attributo e istanza.

I riferimenti agli attributi utilizzano la sintassi standard utilizzata per tutti i riferimenti agli attributi in Python: nome_oggetto. I nomi di attributo validi sono tutti i nomi presenti nello spazio dei nomi della classe al momento della creazione dell'oggetto di classe. Quindi, se la definizione della classe sembrava così:

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

    def f(self):
        return 'hello world'

Un'altra citazione:

In generale, le variabili di istanza sono per dati univoci per ciascuna istanza e le variabili di classe sono per attributi e metodi condivisi da tutte le istanze della classe:

class Dog:

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

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

0

in python3 non c'è differenza, ma in python2 la non estensione objectti dà classi di vecchio stile; ti piacerebbe usare una lezione di nuovo stile rispetto a una lezione di vecchio stile.


2
Questa risposta è ragionevole, ma altri rispondenti sono arrivati ​​più velocemente e / o con maggiori dettagli; questa risposta non aggiunge alcun valore alla pagina così com'è.
Mark Amery,
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.