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