Voglio verificare se un oggetto è un'istanza di una classe e solo questa classe (nessuna sottoclasse). Potrei farlo con:Tipo Python() o __class__, == oppure è
obj.__class__ == Foo
obj.__class__ is Foo
type(obj) == Foo
type(obj) is Foo
Ci sono motivi per scegliere l'uno rispetto all'altro? (differenze di prestazioni, insidie, ecc.)
In altre parole: a) c'è qualche differenza pratica tra l'utilizzo di __class__
e type(x)
? b) gli oggetti di classe sono sempre sicuri per il confronto usando is
?
Update: Grazie a tutti per il feedback. Sono ancora sconcertato dal fatto che gli oggetti di classe siano o meno singleton, il mio buon senso dice che lo sono, ma è stato davvero difficile ottenere una conferma (prova a cercare su google "python", "class" e "unique" o "singleton") .
Mi piacerebbe anche chiarire che, per le mie particolari esigenze, la soluzione "più economica" che funziona è la migliore, dal momento che sto cercando di ottimizzare il massimo da poche classi specializzate (quasi raggiungendo il punto in cui la cosa sensata da fare è far cadere Python e sviluppare quel particolare modulo in C). Ma la ragione alla base della domanda era capire meglio il linguaggio, dal momento che alcune delle sue caratteristiche sono un po 'troppo oscure per me per trovare facilmente quell'informazione. Ecco perché sto lasciando che la discussione si estenda un po 'invece di accontentarsi di __class__ is
, così posso sentire l'opinione di persone più esperte. Finora è stato molto fruttuoso!
Ho eseguito un piccolo test per confrontare le prestazioni delle 4 alternative. I risultati sono stati profiler:
Python PyPy (4x)
type() is 2.138 2.594
__class__ is 2.185 2.437
type() == 2.213 2.625
__class__ == 2.271 2.453
sorprende, is
eseguito meglio di ==
per tutti i casi. type()
ha ottenuto prestazioni migliori in Python (2% più veloce) e __class__
ha ottenuto risultati migliori in PyPy (il 6% più veloce). È interessante notare che __class__ ==
ha ottenuto risultati migliori in PyPy rispetto a type() is
.
Aggiornamento 2: molte persone non sembrano capire cosa intendo con "una classe è un singleton", quindi mi ilustrate con un esempio:
>>> class Foo(object): pass
...
>>> X = Foo
>>> class Foo(object): pass
...
>>> X == Foo
False
>>> isinstance(X(), Foo)
False
>>> isinstance(Foo(), X)
False
>>> x = type('Foo', (object,), dict())
>>> y = type('Foo', (object,), dict())
>>> x == y
False
>>> isinstance(x(), y)
False
>>> y = copy.copy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
>>> y = copy.deepcopy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
doesn Non importa se ci sono oggetti N di tipo type
, dato un oggetto, solo uno sarà la sua classe, quindi è sicuro confrontarsi per riferimento in questo caso. E dal momento che il confronto dei riferimenti sarà sempre più economico rispetto al confronto dei valori, volevo sapere se la mia affermazione precedente valesse o meno. Sto arrivando alla conclusione che lo fa, a meno che qualcuno non presenti prove contrarie.
Se si desidera sapere quale è il più veloce da utilizzare, è sufficiente verificarlo con il modulo timeit. –
Le classi non sono singletons - sono istanze delle loro metaclassi - il metaclass di default è "type", mentre un normale python di Python avrà molte istanze. – jsbueno
@jsbueno Questo non è quello che intendevo. Naturalmente ci sono molte istanze, ma solo una sarà "la classe" di un dato oggetto, giusto? In altre parole se 'x .__ class__ == a' e' a == b' allora 'a is b' (per ben comportarsi' __eq__', ovviamente), questa è la congettura che sto cercando di confermare/confutare. – mgibsonbr