2009-06-29 9 views
35

Qual è la differenza tra type(obj) e obj.__class__? C'è mai una possibilità di type(obj) is not obj.__class__?Differenza tra tipo (obj) e obj .__ class__

Desidero scrivere una funzione che funzioni genericamente sugli oggetti forniti, utilizzando un valore predefinito 1 nello stesso tipo di un altro parametro. Quale variazione, di seguito # 1 o # 2, farà la cosa giusta?

def f(a, b=None): 
    if b is None: 
    b = type(a)(1) # #1 
    b = a.__class__(1) # #2 

risposta

12

type(obj) e type.__class__ non si comportano lo stesso per le classi vecchio stile:

>>> class a(object): 
...  pass 
... 
>>> class b(a): 
...  pass 
... 
>>> class c: 
...  pass 
... 
>>> ai=a() 
>>> bi=b() 
>>> ci=c() 
>>> type(ai) is ai.__class__ 
True 
>>> type(bi) is bi.__class__ 
True 
>>> type(ci) is ci.__class__ 
False 
+7

La più grande ironia è il commento di yairchu ora ha lo stesso problema da quando hanno cambiato la formattazione ..: P –

+10

Non sarebbe male mostrare * come * si comportano in modo diverso, e forse anche * perché *. Il solo dire * quando * si comportano in modo diverso suona una risposta pigra, anche se corretta. – MestreLion

+1

vale la pena menzionare questo è solo il problema in Python 2. In Python 3 tutte e tre le espressioni saranno True. – Bob

30

classi Vecchio stile sono il problema, sospirare:

>>> class old: pass 
... 
>>> x=old() 
>>> type(x) 
<type 'instance'> 
>>> x.__class__ 
<class __main__.old at 0x6a150> 
>>> 

Non è un problema in Python 3 dal momento che tutte le classi sono nuovi in ​​stile ora ;-).

In Python 2, una classe è solo nuovo stile se si eredita da un'altra classe di nuovo stile (tra cui object e le varie tipi built-in, come dict, list, set, ...) o implicitamente o esplicitamente imposta __metaclass__ a type.

+3

È tempo Python 3, che * dovrei * usare? –

+2

Se il tuo codice sta seguendo le migliori pratiche come descritto da Alex, 'type()' sarebbe preferibile. In Python 3, segue sempre le best practice, quindi usa type() in Python 3. –

+0

@AaronHall Sarebbe corretto per me assumere che l'uso di 'type()' è anche preferito su '__class__' se sto scrivendo Python 2 codice in cui so che verrà chiamato solo con istanze di classi di nuovo stile? – kasperd

30

Questa è una vecchia questione, ma nessuna delle risposte sembra di dire che. nel caso generale, si IS possibile per una classe di nuovo stile di avere valori diversi per type(instance) e instance.__class__:

class ClassA(object): 
    def display(self): 
     print("ClassA") 

class ClassB(object): 
    __class__ = ClassA 

    def display(self): 
     print("ClassB") 

instance = ClassB() 

print(type(instance)) 
print(instance.__class__) 
instance.display() 

uscita:

<class '__main__.ClassB'> 
<class '__main__.ClassA'> 
ClassB 

La ragione è che ClassB è prevalente l'__class__ descrittore, tuttavia il campo di tipo interno nell'oggetto non viene modificato. type(instance) legge direttamente da quel campo di tipo, quindi restituisce il valore corretto, mentre instance.__class__ fa riferimento al nuovo descrittore che sostituisce il descrittore originale fornito da Python, che legge il campo del tipo interno. Invece di leggere quel campo di tipo interno, restituisce un valore codificato.

+10

_Caveat lector_: questo dovrebbe essere preso come esempio del perché si dovrebbe evitare di sovrascrivere '__class__'! Si può causare un codice lungo la linea che usa '__class__' per interrompere. –

+0

Interessato anche da '__getattribute__', che intercetta la richiesta per' OBJ .__ class__' ma non per 'type (OBJ)'. – kdb