Class 成员或实例属性?

Class member or instance attribute?

最近一直在使用ctypes中的Structure,但是我遇到了一个奇怪的问题。

这是我的 Python3 代码:

from ctypes import *
class AcknowledgeHeader(Structure):
    _fields_ = [
        ('test', c_uint8),
    ]
ack_header = AcknowledgeHeader()

问题是:test是AcknowledgeHeader的class成员还是ack_header的实例属性?

我试图找到答案。

如果test是ack_header的一个实例属性,那为什么ack_header.__dict__会打印一个空的dict?

if __name__ == '__main__':
    ack_header = AcknowledgeHeader()
    print(ack_header.__dict__)

C:\Users\Administrator\PycharmProjects\gige-lib\venv\Scripts\python.exe
C:/Users/Administrator/PycharmProjects/gige-lib/channel/common.py
{}

Process finished with exit code 0

如果test是AcknowledgeHeader的class成员,那么为什么type(ack_header.test)不等于type(AcknowledgeHeader.test)

if __name__ == '__main__':
    ack_header = AcknowledgeHeader()
    print(type(ack_header.test))
    print(type(AcknowledgeHeader.test))

C:\Users\Administrator\PycharmProjects\gige-lib\venv\Scripts\python.exe C:/Users/Administrator/PycharmProjects/gige-lib/channel/common.py
<class 'int'>
<class '_ctypes.CField'>

Process finished with exit code 0

testAcknowledgeHeader class 上的 数据描述符对象 。在 ack_header 实例上访问它会导致代码 运行 在 C 约定和 Python 类型之间进行转换。

因为它是一个数据描述符,所有与属性的交互都会被捕获,包括删除和赋值。如果您要在 ack_header.__dict__ 属性字典中设置 'test' 键,它会被忽略。

相反,ack_header.test 将始终调用 AcknowledgeHeader.test.__get__(ack_header, AcknowledgeHeader),而分配给 ack_header.test 将触发 AcknowledgeHeader.test.__set__(ack_header, <new value>)

本例中只实现了获取和设置,没有_ctypes.CField.__delete__() method,只有__get____set__,所以del ack_header.test会抛出异常。

有关描述符如何工作的更多详细信息,请参阅 descriptor HOWTO