2016-01-27 8 views
6

stavo leggendo il metodo __init__ della classe del contatore, e ho visto questo:Perché il metodo __init__ del contatore si riferisce a un descrittore?

if not args: 
    TypeError("descriptor '__init__' of 'Counter' object " 
       "needs an argument") 

non ero sicuro di cosa significasse per descrittore, così ho controllato il documento di modello di dati di pitone e abbiamo trovato questo:

In generale, un descrittore è un attributo di oggetto con "comportamento di associazione", uno il cui accesso agli attributi è stato sovrascritto dai metodi nel protocollo descrittore: __get __(), __set __() e __delete __(). Se uno di questi metodi è definito per un oggetto, si dice che sia un descrittore.

Nessuno di questi metodi sembra essere presente nella definizione della classe, quindi perché __init_ si riferisce a come un descrittore?

+0

Per la cronaca, l'unico motivo per cui ha questo design è di consentire l'inizializzazione di un 'Counter' con un argomento di parole chiave' self' senza la sostituzione accidentale dell'istanza 'self' in' __init__'; dovevano accettare varargs posizionali ed estrarre manualmente il "reale" sé, così non aveva un nome esterno che potesse essere sovrascritto da un argomento di parole chiave. Non è possibile attivare questo errore a meno che non si stia chiamando manualmente '__init__' (e lo si fa senza usare' super' in una sottoclasse, che lo passerebbe implicitamente, proprio come una costruzione normale). – ShadowRanger

risposta

4

In python, tutte le funzioni sono descrittori (incluso __init__). Questo è in realtà il modo in cui sanno cosa è self quando vengono utilizzati in una classe. Ad esempio, posso definire una funzione (foo) e poi quando la guardo di metodi, farò in modo che foo ha un metodo __get__ che lo rende aderire al protocollo descrittore:

>>> def foo(): 
... pass 
... 
>>> dir(foo) 
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] 
>>> '__get__' in dir(foo) 
True 

Così la terminologia utilizzata c'è almeno preciso. Potrebbe essere discusso se questo è il termine migliore da usare ...

Potrei averlo chiamato un "metodo Bound" invece di un descrittore, ma in python3.x, la distinzione tra funzioni regolari, metodi associati e metodi non associati diventa un po 'più fangosi (metodi non legato sono funzioni regolari in python3.x) ...


Naturalmente, ho potuto utilizzare un diverso tipo di descrittore per inizializzare il mio Counter sottoclasse ...

class MyDescriptor(object): 
    def __get__(self, inst, cls): 
     # This is a really useless descriptor! 
     return Counter.__init__.__get__(inst, cls) 

class MyCounter(Counter): 
    __init__ = MyDescriptor() 

e lancia un errore, quindi il messaggio di errore sarebbe più accurato in questo modo, ma questo è un caso piuttosto pazzesco che non mi aspetto che succeda molto frequentemente.

Per sapere veramente cosa stava pensando Raymond quando ha scritto quel codice, suppongo che dovresti chiederglielo (o andare a fare lo spelling nella storia del commit di hg e spero di averlo menzionato in un messaggio di commit).

+0

Non capisco la tua risposta e io non capisco perché cada in linea con la documentazione citata. Potresti per favore elaborare? – timgeb

+0

Ah, mi sono perso perché era la funzione che aveva definito \ _ \ _ get__, non Counter. Grazie. –

+0

Correlati: Perché fare riferimento a una funzione come descrittore quando sarebbe più descrittiva (non è previsto il gioco di parole) per chiamarla semplicemente una funzione? –

Problemi correlati