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).
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