我最近了解到,Python不仅有一个名为ctypes
的模块,它有一个docs page,还有一个名为_ctypes
的模块,它是doesn't(尽管如此) mentioned a few times in the docs)。互联网上的某些代码(例如this Stack Overflow answer中的代码段)使用了这个神秘的,未公开说明的_ctypes
模块。
稍作实验,表明这两个模块具有相似但不相同的文档字符串以及重叠但不相同的属性列表:
Python 3.7.4 (default, Sep 7 2019, 18:27:02)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes, _ctypes
>>> print(ctypes.__doc__)
create and manipulate C data types in Python
>>> print(_ctypes.__doc__)
Create and manipulate C compatible data types in Python.
>>> dir(ctypes)
['ARRAY', 'ArgumentError', 'Array', 'BigEndianStructure', 'CDLL', 'CFUNCTYPE', 'DEFAULT_MODE', 'LibraryLoader', 'LittleEndianStructure', 'POINTER', 'PYFUNCTYPE', 'PyDLL', 'RTLD_GLOBAL', 'RTLD_LOCAL', 'SetPointerType', 'Structure', 'Union', '_CFuncPtr', '_FUNCFLAG_CDECL', '_FUNCFLAG_PYTHONAPI', '_FUNCFLAG_USE_ERRNO', '_FUNCFLAG_USE_LASTERROR', '_Pointer', '_SimpleCData', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', '_c_functype_cache', '_calcsize', '_cast', '_cast_addr', '_check_size', '_ctypes_version', '_dlopen', '_endian', '_memmove_addr', '_memset_addr', '_os', '_pointer_type_cache', '_reset_cache', '_string_at', '_string_at_addr', '_sys', '_wstring_at', '_wstring_at_addr', 'addressof', 'alignment', 'byref', 'c_bool', 'c_buffer', 'c_byte', 'c_char', 'c_char_p', 'c_double', 'c_float', 'c_int', 'c_int16', 'c_int32', 'c_int64', 'c_int8', 'c_long', 'c_longdouble', 'c_longlong', 'c_short', 'c_size_t', 'c_ssize_t', 'c_ubyte', 'c_uint', 'c_uint16', 'c_uint32', 'c_uint64', 'c_uint8', 'c_ulong', 'c_ulonglong', 'c_ushort', 'c_void_p', 'c_voidp', 'c_wchar', 'c_wchar_p', 'cast', 'cdll', 'create_string_buffer', 'create_unicode_buffer', 'get_errno', 'memmove', 'memset', 'pointer', 'py_object', 'pydll', 'pythonapi', 'resize', 'set_errno', 'sizeof', 'string_at', 'wstring_at']
>>> dir(_ctypes)
['ArgumentError', 'Array', 'CFuncPtr', 'FUNCFLAG_CDECL', 'FUNCFLAG_PYTHONAPI', 'FUNCFLAG_USE_ERRNO', 'FUNCFLAG_USE_LASTERROR', 'POINTER', 'PyObj_FromPtr', 'Py_DECREF', 'Py_INCREF', 'RTLD_GLOBAL', 'RTLD_LOCAL', 'Structure', 'Union', '_Pointer', '_SimpleCData', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '__version__', '_cast_addr', '_memmove_addr', '_memset_addr', '_pointer_type_cache', '_string_at_addr', '_unpickle', '_wstring_at_addr', 'addressof', 'alignment', 'buffer_info', 'byref', 'call_cdeclfunction', 'call_function', 'dlclose', 'dlopen', 'dlsym', 'get_errno', 'pointer', 'resize', 'set_errno', 'sizeof']
我暂时以为也许我看到的是一个"accelerator module",但是我认为不可能,因为current implementation of ctypes
无条件从{{1 }}。也不清楚_ctypes
只是实现细节;它公开了至少一个公共成员_ctypes
,这是有用的,不能通过PyObj_FromPtr
模块使用,并且在CPython源代码中没有使用过-也许表明这是供我们导入并使用的,编写Python代码?
Python为什么这两个模块的名称基本相同?两者之间的职责划分是什么,我何时要在另一种之上使用?我应该将ctypes
视为标准库的一部分,还是不应接触的实现细节?
答案 0 :(得分:6)
_ctypes
之所以存在是因为必须用C编写大量的ctypes
。ctypes
和_ctypes
两者之所以存在是因为并非全部ctypes
中的C必须用C编写。ctypes
包含用Python编写更方便的部分。
_ctypes
内含没有前导下划线且未被ctypes
暴露的事实,并不意味着这些内容将被任何东西使用。有时程序只是像那样留有东西。可能有意在开发的某个时刻将其公开。
_ctypes
是实现细节。使用ctypes
。