Domanda

Qual è la differenza tra vecchio e nuovo stile di classi in Python?Quando devo usare l'uno o l'altro?

È stato utile?

Soluzione

Da http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes :

Fino a Python 2.1, vecchio stile, le classi sono il solo gusto disponibile per l'utente.

Il concetto di (vecchio stile), la classe non è correlato al concetto del tipo:se x è un'istanza di un vecchio stile, classe, quindi x.__class__ indica la classe di x, ma type(x) è sempre <type 'instance'>.

Questo riflette il fatto che tutti i vecchi stile istanze, indipendentemente la loro classe, sono attuate con un unico built-in tipo, chiamato esempio.

Il nuovo stile di classi sono state introdotte in Python 2.2 di unificare i concetti di classe e di tipo.Un nuovo stile di classe è semplicemente un tipo definito dall'utente, niente di più, niente di meno.

Se x è un'istanza di un nuovo stile di classe, quindi type(x) in genere è lo stesso x.__class__ (anche se questo non è garantito un stile nuova istanza della classe è consentito sostituire il valore restituito per x.__class__).

La principale motivazione per l'introduzione di nuovi-classi di stile è quello di fornire un unificata modello a oggetti con un pieno di meta-modello.

Essa ha anche un certo numero di benefici immediati, come la capacità di sottoclasse maggior parte dei tipi predefiniti, o l'introduzione di "descrittori", che consentono calcolata proprietà.

Per ragioni di compatibilità, le classi sono ancora vecchio stile per impostazione predefinita.

Il nuovo stile di classi vengono creati specificando un altro stile nuova classe (cioètipo a), come parte di un genitore della classe, o il "primo livello" tipo di oggetto se non altro genitore è necessaria.

Il comportamento delle nuove classi di stile è diverso da quello del vecchio stile le classi in una serie di importanti dettagli in aggiunta al tipo restituisce.

Alcuni di questi cambiamenti sono fondamentali per il nuovo modello di oggetto, come il modo speciale i metodi vengono richiamati.Gli altri sono "correzioni" che non poteva essere attuate prima per problemi di compatibilità, come il metodo l'ordine di risoluzione in caso di ereditarietà multipla.

Python 3 ha solo il nuovo stile di classi di.

Non importa se si sottoclasse dal object o non, le classi sono il nuovo stile di in Python 3.

Altri suggerimenti

Dichiarazione-saggi:

Il nuovo stile di classi ereditano da un oggetto o da un altro nuovo stile di classe.

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

Old-classi di stile non.

class OldStyleClass():
    pass

Importanti cambiamenti di comportamento tra il vecchio e il nuovo stile classi

  • super aggiunto
  • MRO cambiato (spiegato di seguito)
  • descrittori aggiunto
  • nuovo stile oggetti di classe non può essere elevato a meno che non derivati da Exception (esempio sotto)
  • __slots__ aggiunto

MRO (Metodo di Risoluzione Ordine) cambiato

È stato già detto in altre risposte, ma qui va un concreto esempio della differenza tra il classico MRO e C3 (MRO utilizzato in nuove classi di stile).

La domanda è: l'ordine in cui gli attributi (che includono i metodi e le variabili membro) sono cercato in più di un'eredità.

Classico classi fare una approfondita ricerca da sinistra a destra.Fermati alla prima partita.Non hanno il __mro__ attributo.

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
    C12.__mro__
except AttributeError:
    pass
else:
    assert False

Nuovo stile classi MRO è più complicato sintetizzare in una sola frase in inglese.Si è spiegata in dettaglio qui.Una delle sue caratteristiche è che una classe Base è solo cercato una volta che tutte le classi Derivate sono state.Essi hanno il __mro__ attributo che indica l'ordine di ricerca.

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

Nuovo stile oggetti di classe non può essere elevato a meno che non derivati da Exception

Intorno a Python 2.5 molte classi possono essere elevato, intorno Python 2.6 questo è stato rimosso.Su Python 2.7.3:

# OK, old:
class Old: pass
try:
    raise Old()
except Old:
    pass
else:
    assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
    raise New()
except TypeError:
    pass
else:
    assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
    raise New()
except New:
    pass
else:
    assert False

# `'str'` is a new style object, so you can't raise it:
try:
    raise 'str'
except TypeError:
    pass
else:
    assert False

Vecchio stile, le classi sono ancora marginalmente più veloce per l'attributo di ricerca.Di solito questo non è importante, ma può essere utile in termini di prestazioni sensibile Python 2.x codice:

In [3]: class A:
   ...:     def __init__(self):
   ...:         self.a = 'hi there'
   ...: 

In [4]: class B(object):
   ...:     def __init__(self):
   ...:         self.a = 'hi there'
   ...: 

In [6]: aobj = A()
In [7]: bobj = B()

In [8]: %timeit aobj.a
10000000 loops, best of 3: 78.7 ns per loop

In [10]: %timeit bobj.a
10000000 loops, best of 3: 86.9 ns per loop

Guido ha scritto La Storia Nuova in Stile Classi, davvero un grande articolo su nuovo stile e il vecchio stile di classe in Python.

Python 3 ha solo il nuovo stile di classe, anche se si scrive un 'vecchio stile, classe', è implicitamente derivati da object.

Il nuovo stile di classi hanno alcune caratteristiche avanzate manca nel vecchio stile classi, come il super e il nuovo C3 mro, alcuni magico metodi, etc.

Ecco un molto pratico, Vero/Falso differenza.L'unica differenza tra le due versioni di codice riportato di seguito è che nella seconda versione la Persona eredita da object.Diverso da quello che le due versioni sono identiche, ma con risultati diversi :

1) vecchio stile classi

class Person():
    _names_cache = {}
    def __init__(self,name):
        self.name = name
    def __new__(cls,name):
        return cls._names_cache.setdefault(name,object.__new__(cls,name))

ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed1 is ahmed2
print ahmed1
print ahmed2


>>> False
<__main__.Person instance at 0xb74acf8c>
<__main__.Person instance at 0xb74ac6cc>
>>>

2) il nuovo stile di classi di

class Person(object):
    _names_cache = {}
    def __init__(self,name):
        self.name = name
    def __new__(cls,name):
        return cls._names_cache.setdefault(name,object.__new__(cls,name))

ahmed1 = Person("Ahmed")
ahmed2 = Person("Ahmed")
print ahmed2 is ahmed1
print ahmed1
print ahmed2

>>> True
<__main__.Person object at 0xb74ac66c>
<__main__.Person object at 0xb74ac66c>
>>>

Il nuovo stile di classi ereditano da object e deve essere scritta come tale in Python 2.2 in poi (cioè class Classname(object): invece di class Classname:).Il cambiamento radicale è quello di unificare i tipi e le classi, e il piacevole effetto collaterale di questo è che permette di ereditare dal built-in tipi.

Leggi descrintro per ulteriori dettagli.

Nuovo stile classi possono utilizzare super(Foo, self) dove Foo è una classe e self è l'istanza.

super(type[, object-or-type])

Restituire un oggetto proxy che i delegati chiamate di metodo per un genitore o un fratello classe di tipo.Questo è utile per accedere a metodi ereditati che sono stato sottoposto a override in una classe.L'ordine di ricerca è uguale a quello utilizzato da getattr() tranne che il tipo è saltato.

E in Python 3.x si può semplicemente utilizzare super() all'interno di una classe senza parametri.

O, piuttosto, si dovrebbe sempre utilizzare il nuovo stile di classi, a meno che non è necessario che il codice ha bisogno di lavorare con le versioni di Python di età superiore a 2.2.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top