2016-01-27 3 views
6

Я читал метод __init__ класса счетчика, и увидел это:Почему метод __init__ счетчика называется дескриптором?

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

Я не был уверен, что он имел в виду дескриптором, поэтому я проверил модель данных питона документ и нашел это:

В целом дескриптор - это атрибут объекта с «поведением привязки», тот, чей доступ к атрибуту был переопределен методами в протоколе дескриптора: __get __(), __set __() и __delete __(). Если какой-либо из этих методов определен для объекта, он называется дескриптором.

Ни один из этих методов не присутствует в определении класса, поэтому почему __init_ называется дескриптором?

+0

Для записи единственная причина, по которой он имеет этот дизайн, - разрешить инициализацию «Counter» с помощью аргумента ключевого слова с именем «self» без случайной замены экземпляра 'self' в' __init__'; они должны были принимать позиционные varargs и вручную извлекать «реальный» 'self', поэтому у него не было внешнего имени, которое могло бы быть переопределено аргументом ключевого слова. Вы не можете инициировать эту ошибку, если только вы не вызываете вручную '__init__' (и делаете это, не используя' super' в подклассе, который будет передавать его неявно, как обычная конструкция). – ShadowRanger

ответ

4

В python, все функции являются дескрипторами (включая __init__). На самом деле они знают, что такое self, когда они используются в классе. Например, я могу определить функцию (foo), а затем, когда я смотрю на это методы, я буду видеть, что foo имеет __get__ метод, позволяющий придерживаться протокола дескриптора:

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

Таким образом, терминология, используемая есть как минимум точный. Можно было бы обсудить, будет ли это лучший термин для использования ...

Возможно, я назвал его «связанным методом» вместо дескриптора, но в python3.x, различие между регулярными функциями, связанными методами и несвязанными методами становится немного более мутными (несвязанные методами являются регулярными функциями в python3.x) ...


конечно, я мог бы использовать другой тип дескриптора для инициализации моего Counter подкласса ...

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

и выбросить ошибку, тогда сообщение об ошибке будет более точным таким образом, но это довольно сумасшедший случай, который я не ожидал бы очень часто.

Чтобы действительно знать, что думал Раймонд, когда писал этот код, я предполагаю, что вам придется попросить его (или перейти в историю фиксации hg и надеяться, что он упомянул об этом в сообщении о фиксации).

+0

Я не понимаю вашего ответа, и я дважды не понимаю, как это соответствует приведенной документации. Не могли бы вы рассказать? – timgeb

+0

А я пропустил, что это была функция, которая определила \ _ \ _ get__, а не Counter. Благодарю. –

+0

Связано: Зачем ссылаться на функцию как дескриптор, когда она будет более описательной (не предназначенной для каламбура), чтобы просто назвать ее функцией? –

Смежные вопросы