为什么将 Counter 的 __init__ 方法称为描述符?

Why is the __init__ method of Counter referred to as a descriptor?

我正在阅读计数器 class 的 __init__ 方法,看到了这个:

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

我不确定描述符是什么意思,所以我检查了 python 数据模型文档并发现了这个:

In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol: __get__(), __set__(), and __delete__(). If any of those methods are defined for an object, it is said to be a descriptor.

None 这些方法似乎出现在 class 定义中,那么为什么 __init_ 被称为描述符?

在python中,所有函数都是描述符(包括__init__)。当他们在 class 中使用时,这实际上就是他们知道 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

所以那里使用的术语至少准确。可以争论这是否是使用的最佳术语...

我可能称它为 "Bound method" 而不是描述符,但在 python3.x 中,常规函数、绑定方法和未绑定方法之间的区别变得有点模糊(未绑定方法 python3.x)...

中的常规函数

当然,我可以使用不同类型的描述符来初始化我的 Counter subclass ...

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

并抛出错误,这样错误消息会更准确,但这是一个非常疯狂的案例,我不希望经常发生。

要真正了解 Raymond 在编写该代码时的想法,我想您必须问他(或者去 hg 提交历史中探索并希望他在提交消息中提到它)。