2013-12-15 2 views
9

Qual è lo scopo di controllare self.__class__? Ho trovato un codice che crea una classe di interfaccia astratta e quindi controlla se il suo self.__class__ è esso stesso, ad es.Qual è lo scopo di controllare self .__ class__? - python

class abstract1 (object): 
    def __init__(self): 
    if self.__class__ == abstract1: 
     raise NotImplementedError("Interfaces can't be instantiated") 

Qual è lo scopo? Verifica se la classe è un tipo di se stesso?

Il codice è dal di NLTK http://nltk.googlecode.com/svn/trunk/doc/api/nltk.probability-pysrc.html#ProbDistI

+1

Penso che questo richieda più contesto. Dove hai "trovato" questo codice? È fondamentalmente rotto. – Iguananaut

+1

@Iguananaut: Perché è rotto? Funziona bene * se usato come previsto; come una classe base astratta. –

+1

Sono abbastanza sicuro prima era qualcosa di diverso? Non lo so - sono d'accordo, quello che c'è ora non è rotto. – Iguananaut

risposta

15

self.__class__ è un riferimento al tipo dell'istanza corrente.

Per le istanze di abstract1, che sarebbe il abstract1 classe , che è quello che non si vuole con una classe astratta. classi astratte sono solo scopo di essere sottoclasse, non creare istanze direttamente:

>>> abstract1() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 4, in __init__ 
NotImplementedError: Interfaces can't be instantiated 

Per un esempio di un sottoclasse di abstract1, self.__class__ sarebbe un riferimento alla sottoclasse specifica:

>>> class Foo(abstract1): pass 
... 
>>> f = Foo() 
>>> f.__class__ 
<class '__main__.Foo'> 
>>> f.__class__ is Foo 
True 

Lanciare un'eccezione qui è come usare un'istruzione assert altrove nel codice, che ti protegge da errori stupidi.

noti che il pythonic modo per verificare il tipo di un'istanza è utilizzare il type() function invece, insieme ad un prova identità con la is esercente:

class abstract1(object): 
    def __init__(self): 
     if type(self) is abstract1: 
      raise NotImplementedError("Interfaces can't be instantiated") 

C'è poco senso utilizzando un test di uguaglianza qui come per le classi personalizzate, lo __eq__ è praticamente implementato comunque come test di identità.

Python include anche una libreria standard per definire le classi di base astratte, chiamate abc. Ti consente di contrassegnare metodi e proprietà come astratti e rifiuterà di creare istanze di qualsiasi sottoclasse che non abbia ancora ridefinito quei nomi.

1

Il codice che hai postato c'è una no-op; self.__class__ == c1 non fa parte di un condizionale, quindi il valore booleano viene valutato ma non viene eseguito nulla con il risultato.

Si potrebbe provare a creare una classe base astratta che verifichi se self.__class__ è uguale alla classe astratta rispetto a un bambino ipotetico (tramite un'istruzione if), per impedire l'istanziazione della classe base astratta stessa a causa di errore dello sviluppatore.

+1

Anche se per le versioni più recenti di Python si dovrebbe semplicemente usare una classe base astratta usando 'abc.ABCMeta'. – Iguananaut

+0

Un ABC può ancora essere istanziato direttamente. –

1

direi che alcuni vorrebbero fare:

class Foo(AbstractBase): 
    def __init__(self): 
     super(Foo, self).__init__() 
     # ... 

Anche quando la base è astratta, non vorrebbe del __init__ base per lanciare NotImplementedError. Ehi, forse fa qualcosa di utile?

+0

Stai dicendo che 'super (Foo, self) .__ init __()' non funzionerebbe? Perché non è corretto; funzionerà * bene *. La '__init__' della base * * * solleva l'eccezione quando self è un'istanza di' AbstractBase', e non quando è un'istanza di una sottoclasse come 'Foo'. –

0

Gli indizi sono nel nome della classe, "abstract1" e nell'errore. Questo è inteso per essere una classe astratta, che significa uno che è destinato a essere sottoclasse. Ogni sottoclasse fornirà il proprio comportamento. La classe astratta stessa serve a documentare l'interfaccia, cioè i metodi e gli argomenti che dovrebbero avere le classi che implementano l'interfaccia. Non è pensato per essere istanziato stesso, e il test è usato per dire se siamo nella classe stessa o in una sottoclasse.

Vedere la sezione sulle classi astratte in questo article di Julien Danjou.

1

Qual è lo scopo? È per verificare se la classe è un tipo di se stesso?

Sì, se si tenta di costruire un oggetto di tipo Abstract1 verrà generata tale eccezione che ti dice che non sei autorizzato a farlo.