为什么将 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 提交历史中探索并希望他在提交消息中提到它)。
我正在阅读计数器 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 提交历史中探索并希望他在提交消息中提到它)。