ctypes — Python用の外部関数ライブラリ—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.9/library/ctypes
移動先:案内検索

ctypes —Python用の外部関数ライブラリ


ctypes は、Python用の外部関数ライブラリです。 C互換のデータ型を提供し、DLLまたは共有ライブラリで関数を呼び出すことができます。 これらのライブラリを純粋なPythonでラップするために使用できます。

ctypesチュートリアル

注:このチュートリアルのコードサンプルでは、 doctest を使用して、実際に機能することを確認しています。 一部のコードサンプルは、Linux、Windows、またはmacOSで動作が異なるため、コメントにdoctestディレクティブが含まれています。

注:一部のコードサンプルは、ctypes c_int タイプを参照しています。 sizeof(long) == sizeof(int)のプラットフォームでは、 c_long のエイリアスです。 したがって、 c_int を期待する場合、 c_long が出力されても、混乱しないでください。実際には同じ型です。

ロードされたdllから関数にアクセスする

関数は、dllオブジェクトの属性としてアクセスされます。

>>> from ctypes import *
>>> libc.printf
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.GetModuleHandleA)  
<_FuncPtr object at 0x...>
>>> print(windll.kernel32.MyOwnFunction)     
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ctypes.py", line 239, in __getattr__
    func = _StdcallFuncPtr(name, self)
AttributeError: function 'MyOwnFunction' not found
>>>

kernel32user32などのwin32システムdllは、関数のUNICODEバージョンだけでなくANSIバージョンもエクスポートすることが多いことに注意してください。 UNICODEバージョンは名前にWが追加されてエクスポートされ、ANSIバージョンは名前にAが追加されてエクスポートされます。 指定されたモジュール名のモジュールハンドルを返すwin32 GetModuleHandle関数には、次のCプロトタイプがあり、マクロを使用してそれらの1つをGetModuleHandleとして公開します。 UNICODEが定義されているかどうかに応じて:

/* ANSI version */
HMODULE GetModuleHandleA(LPCSTR lpModuleName);
/* UNICODE version */
HMODULE GetModuleHandleW(LPCWSTR lpModuleName);

windll は魔法でそれらの1つを選択しようとはしません。GetModuleHandleAまたはGetModuleHandleWを明示的に指定して必要なバージョンにアクセスし、バイトまたは文字列で呼び出す必要がありますそれぞれオブジェクト。

"??2@YAPAXI@Z"のように、dllが有効なPython識別子ではない名前で関数をエクスポートすることがあります。 この場合、関数を取得するには getattr()を使用する必要があります。

>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")  
<_FuncPtr object at 0x...>
>>>

Windowsでは、一部のdllは、名前ではなく序数で関数をエクスポートします。 これらの関数には、dllオブジェクトに序数のインデックスを付けることでアクセスできます。

>>> cdll.kernel32[1]  
<_FuncPtr object at 0x...>
>>> cdll.kernel32[0]  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ctypes.py", line 310, in __getitem__
    func = _StdcallFuncPtr(name, self)
AttributeError: function ordinal 0 not found
>>>

関数の呼び出し

これらの関数は、他のPython呼び出し可能オブジェクトと同じように呼び出すことができます。 この例では、Unixエポックからのシステム時間を秒単位で返すtime()関数と、win32モジュールハンドルを返すGetModuleHandleA()関数を使用しています。

この例では、NULLポインターを使用して両方の関数を呼び出します(NoneNULLポインターとして使用する必要があります)。

>>> print(libc.time(None))  
1150640792
>>> print(hex(windll.kernel32.GetModuleHandleA(None)))  
0x1d000000
>>>

ValueError は、stdcall関数をcdecl呼び出し規約で呼び出すと発生します。その逆も同様です。

>>> cdll.kernel32.GetModuleHandleA(None)  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with not enough arguments (4 bytes missing)
>>>

>>> windll.msvcrt.printf(b"spam")  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Procedure probably called with too many arguments (4 bytes in excess)
>>>

正しい呼び出し規約を見つけるには、Cヘッダーファイルまたは呼び出したい関数のドキュメントを調べる必要があります。

Windowsでは、 ctypes はwin32構造化例外処理を使用して、関数が無効な引数値で呼び出された場合の一般保護違反によるクラッシュを防ぎます。

>>> windll.kernel32.GetModuleHandleA(32)  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: exception: access violation reading 0x00000020
>>>

ただし、Pythonを ctypes でクラッシュさせるには十分な方法があるため、とにかく注意する必要があります。 faulthandler モジュールは、クラッシュのデバッグに役立ちます(例: 誤ったCライブラリ呼び出しによって生成されたセグメンテーション違反から)。

None、整数、バイトオブジェクト、および(Unicode)文字列は、これらの関数呼び出しでパラメーターとして直接使用できる唯一のネイティブPythonオブジェクトです。 NoneはC NULLポインターとして渡され、バイトオブジェクトと文字列は、データを含むメモリブロック( char * または wchar_t *)へのポインターとして渡されます。 )。 Python整数は、プラットフォームのデフォルトのC int 型として渡され、その値はC型に収まるようにマスクされます。

他のパラメーター型を使用した関数の呼び出しに進む前に、 ctypes データ型について詳しく学ぶ必要があります。


基本的なデータ型

ctypes は、いくつかのプリミティブC互換データ型を定義します。

ctypesタイプ Cタイプ Pythonタイプ
c_bool _Bool ブール(1)
c_char char 1文字バイトオブジェクト
c_wchar wchar_t 1文字の文字列
c_byte char int
c_ubyte unsigned char int
c_short 短い int
c_ushort 署名されていない短い int
c_int int int
c_uint unsigned int int
c_long 長さ int
c_ulong unsigned long int
c_longlong __int64または long long int
c_ulonglong unsigned __int64 または unsigned long long int
c_size_t size_t int
c_ssize_t ssize_tまたはPy_ssize_t int
c_float 浮く 浮く
c_double ダブル 浮く
c_longdouble ロングダブル 浮く
c_char_p char * (NUL終了) バイトオブジェクトまたはNone
c_wchar_p wchar_t * (NUL終了) 文字列またはNone
c_void_p 空所* intまたはNone
  1. コンストラクターは、真理値を持つすべてのオブジェクトを受け入れます。

これらのタイプはすべて、正しいタイプと値のオプションのイニシャライザーを使用して呼び出すことで作成できます。

>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p(140018365411392)
>>> c_ushort(-3)
c_ushort(65533)
>>>

これらのタイプは変更可能であるため、後で値を変更することもできます。

>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99
>>>

ポインタ型 c_char_pc_wchar_p 、および c_void_p のインスタンスに新しい値を割り当てると、それらが指すメモリ位置が変更されます[X169X ]メモリブロックの内容ではありません(もちろん、Pythonバイトオブジェクトは不変であるため、そうではありません):

>>> s = "Hello, World"
>>> c_s = c_wchar_p(s)
>>> print(c_s)
c_wchar_p(139966785747344)
>>> print(c_s.value)
Hello World
>>> c_s.value = "Hi, there"
>>> print(c_s)              # the memory location has changed
c_wchar_p(139966783348904)
>>> print(c_s.value)
Hi, there
>>> print(s)                # first object is unchanged
Hello, World
>>>

ただし、可変メモリへのポインタを期待する関数にそれらを渡さないように注意する必要があります。 可変メモリブロックが必要な場合、ctypesには create_string_buffer()関数があり、さまざまな方法でこれらを作成します。 現在のメモリブロックの内容は、rawプロパティを使用してアクセス(または変更)できます。 NULで終了する文字列としてアクセスする場合は、valueプロパティを使用します。

>>> from ctypes import *
>>> p = create_string_buffer(3)            # create a 3 byte buffer, initialized to NUL bytes
>>> print(sizeof(p), repr(p.raw))
3 b'\x00\x00\x00'
>>> p = create_string_buffer(b"Hello")     # create a buffer containing a NUL terminated string
>>> print(sizeof(p), repr(p.raw))
6 b'Hello\x00'
>>> print(repr(p.value))
b'Hello'
>>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
>>> print(sizeof(p), repr(p.raw))
10 b'Hello\x00\x00\x00\x00\x00'
>>> p.value = b"Hi"
>>> print(sizeof(p), repr(p.raw))
10 b'Hi\x00lo\x00\x00\x00\x00\x00'
>>>

create_string_buffer()関数は、c_buffer()関数(エイリアスとして引き続き使用可能)、および以前のctypesリリースのc_string()関数を置き換えます。 Cタイプwchar_tのUnicode文字を含む可変メモリブロックを作成するには、 create_unicode_buffer()関数を使用します。


関数の呼び出し、続き

printfは実際の標準出力チャネルではなくから sys.stdout に出力するため、これらの例はコンソールプロンプトでのみ機能し、 IDLE 内からは機能しないことに注意してください。または PythonWin

>>> printf = libc.printf
>>> printf(b"Hello, %s\n", b"World!")
Hello, World!
14
>>> printf(b"Hello, %S\n", "World!")
Hello, World!
14
>>> printf(b"%d bottles of beer\n", 42)
42 bottles of beer
19
>>> printf(b"%f bottles of beer\n", 42.5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2
>>>

前に述べたように、整数、文字列、バイトオブジェクトを除くすべてのPython型は、必要なCデータ型に変換できるように、対応する ctypes 型でラップする必要があります。

>>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
An int 1234, a double 3.140000
31
>>>

独自のカスタムデータ型を使用した関数の呼び出し

ctypes 引数の変換をカスタマイズして、独自のクラスのインスタンスを関数の引数として使用できるようにすることもできます。 ctypes_as_parameter_属性を探し、これを関数の引数として使用します。 もちろん、整数、文字列、またはバイトのいずれかである必要があります。

>>> class Bottles:
...     def __init__(self, number):
...         self._as_parameter_ = number
...
>>> bottles = Bottles(42)
>>> printf(b"%d bottles of beer\n", bottles)
42 bottles of beer
19
>>>

インスタンスのデータを_as_parameter_インスタンス変数に保存したくない場合は、プロパティを定義して、要求に応じて属性を使用できるようにすることができます。


必要な引数タイプの指定(関数プロトタイプ)

argtypes属性を設定することにより、DLLからエクスポートされる関数の必須引数タイプを指定することができます。

argtypesはCデータ型のシーケンスである必要があります(printf関数は、フォーマット文字列に応じて可変数とさまざまなタイプのパラメーターを受け取るため、ここではおそらく良い例ではありません。一方、これはこの機能を試すのに非常に便利です):

>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
>>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)
String 'Hi', Int 10, Double 2.200000
37
>>>

形式を指定すると、互換性のない引数タイプから保護され(C関数のプロトタイプと同様)、引数を有効なタイプに変換しようとします。

>>> printf(b"%d %d %d", 1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: wrong type
>>> printf(b"%s %d %f\n", b"X", 2, 3)
X 2 3.000000
13
>>>

関数呼び出しに渡す独自のクラスを定義した場合、それらをargtypesシーケンスで使用できるようにするには、from_param()クラスメソッドを実装する必要があります。 from_param()クラスメソッドは、関数呼び出しに渡されたPythonオブジェクトを受け取ります。タイプチェックなど、このオブジェクトが受け入れ可能であることを確認するために必要な処理を実行してから、オブジェクト自体、その_as_parameter_を返します。属性、またはこの場合はC関数の引数として渡したいもの。 この場合も、結果は整数、文字列、バイト、 ctypes インスタンス、または_as_parameter_属性を持つオブジェクトになります。


返品タイプ

デフォルトでは、関数はC int タイプを返すと想定されています。 関数オブジェクトのrestype属性を設定することにより、他の戻りタイプを指定できます。

より高度な例を次に示します。strchr関数を使用します。この関数は、文字列ポインターと文字を予期し、文字列へのポインターを返します。

>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))  
8059983
>>> strchr.restype = c_char_p    # c_char_p is a pointer to a string
>>> strchr(b"abcdef", ord("d"))
b'def'
>>> print(strchr(b"abcdef", ord("x")))
None
>>>

上記のord("x")呼び出しを回避したい場合は、argtypes属性を設定すると、2番目の引数が1文字のPythonバイトオブジェクトからC文字に変換されます。

>>> strchr.restype = c_char_p
>>> strchr.argtypes = [c_char_p, c_char]
>>> strchr(b"abcdef", b"d")
'def'
>>> strchr(b"abcdef", b"def")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ArgumentError: argument 2: exceptions.TypeError: one character string expected
>>> print(strchr(b"abcdef", b"x"))
None
>>> strchr(b"abcdef", b"d")
'def'
>>>

外部関数が整数を返す場合は、呼び出し可能なPythonオブジェクト(関数やクラスなど)をrestype属性として使用することもできます。 呼び出し可能オブジェクトは、C関数が返す integer で呼び出され、この呼び出しの結果が関数呼び出しの結果として使用されます。 これは、エラーの戻り値をチェックし、自動的に例外を発生させるのに役立ちます。

>>> GetModuleHandle = windll.kernel32.GetModuleHandleA  
>>> def ValidHandle(value):
...     if value == 0:
...         raise WinError()
...     return value
...
>>>
>>> GetModuleHandle.restype = ValidHandle  
>>> GetModuleHandle(None)  
486539264
>>> GetModuleHandle("something silly")  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in ValidHandle
OSError: [Errno 126] The specified module could not be found.
>>>

WinErrorは、Windows FormatMessage() apiを呼び出してエラーコードの文字列表現を取得する関数であり、例外を返します。 WinErrorは、オプションのエラーコードパラメータを取ります。誰も使用されていない場合は、 GetLastError()を呼び出して取得します。

errcheck属性を使用すると、はるかに強力なエラーチェックメカニズムを利用できることに注意してください。 詳細については、リファレンスマニュアルを参照してください。


ポインターの受け渡し(または:参照によるパラメーターの受け渡し)

C api関数は、データ型へのポインターをパラメーターとして期待する場合があります。おそらく、対応する場所に書き込むか、データが大きすぎて値を渡すことができない場合です。 これは、参照によるパラメータの受け渡しとも呼ばれます。

ctypes は、参照によってパラメーターを渡すために使用される byref()関数をエクスポートします。 pointer()関数でも同じ効果が得られますが、 pointer()は実際のポインターオブジェクトを構築するため、より多くの作業を行うため、を使用する方が高速です。 ] byref() Python自体にポインタオブジェクトが必要ない場合:

>>> i = c_int()
>>> f = c_float()
>>> s = create_string_buffer(b'\000' * 32)
>>> print(i.value, f.value, repr(s.value))
0 0.0 b''
>>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s",
...             byref(i), byref(f), s)
3
>>> print(i.value, f.value, repr(s.value))
1 3.1400001049 b'Hello'
>>>

構造体と共用体

構造体と共用体は、 ctypes モジュールで定義されている Structure および Union 基本クラスから派生する必要があります。 各サブクラスは、_fields_属性を定義する必要があります。 _fields_は、フィールド名フィールドタイプを含む 2タプルのリストである必要があります。

フィールドタイプは、 c_int のような ctypes タイプ、またはその他の派生 ctypes タイプ(構造体、共用体、配列、ポインター)である必要があります。

これは、 x および y という名前の2つの整数を含むPOINT構造体の簡単な例であり、コンストラクターで構造体を初期化する方法も示しています。

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = [("x", c_int),
...                 ("y", c_int)]
...
>>> point = POINT(10, 20)
>>> print(point.x, point.y)
10 20
>>> point = POINT(y=5)
>>> print(point.x, point.y)
0 5
>>> POINT(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: too many initializers
>>>

ただし、はるかに複雑な構造を構築することはできます。 構造体をフィールドタイプとして使用することにより、構造体自体に他の構造体を含めることができます。

これは、左上右下という名前の2つのポイントを含むRECT構造です。

>>> class RECT(Structure):
...     _fields_ = [("upperleft", POINT),
...                 ("lowerright", POINT)]
...
>>> rc = RECT(point)
>>> print(rc.upperleft.x, rc.upperleft.y)
0 5
>>> print(rc.lowerright.x, rc.lowerright.y)
0 0
>>>

ネストされた構造体は、コンストラクターでいくつかの方法で初期化することもできます。

>>> r = RECT(POINT(1, 2), POINT(3, 4))
>>> r = RECT((1, 2), (3, 4))

フィールド記述子クラスから取得できます。これらは有用な情報を提供できるため、デバッグに役立ちます。

>>> print(POINT.x)
<Field type=c_long, ofs=0, size=4>
>>> print(POINT.y)
<Field type=c_long, ofs=4, size=4>
>>>

警告

ctypes は、ビットフィールドを持つユニオンまたは構造体を値で関数に渡すことをサポートしていません。 これは32ビットx86で機能する可能性がありますが、一般的なケースで機能することがライブラリによって保証されていません。 ビットフィールドを持つ共用体と構造体は、常にポインタによって関数に渡される必要があります。


構造体/共用体の配置とバイト順序

デフォルトでは、StructureフィールドとUnionフィールドは、Cコンパイラと同じ方法で配置されます。 サブクラス定義で_pack_クラス属性を指定することにより、この動作をオーバーライドすることができます。 これは正の整数に設定する必要があり、フィールドの最大配置を指定します。 これは、#pragma pack(n)がMSVCでも行うことです。

ctypes は、構造体と共用体のネイティブバイト順序を使用します。 非ネイティブバイトオーダーの構造を構築するには、 BigEndianStructureLittleEndianStructureBigEndianUnion、およびLittleEndianUnion基本クラスのいずれかを使用できます。 これらのクラスにポインタフィールドを含めることはできません。


構造体と共用体のビットフィールド

ビットフィールドを含む構造体と共用体を作成することが可能です。 ビットフィールドは整数フィールドでのみ可能です。ビット幅は、_fields_タプルの3番目の項目として指定されます。

>>> class Int(Structure):
...     _fields_ = [("first_16", c_int, 16),
...                 ("second_16", c_int, 16)]
...
>>> print(Int.first_16)
<Field type=c_long, ofs=0:0, bits=16>
>>> print(Int.second_16)
<Field type=c_long, ofs=0:16, bits=16>
>>>

配列

配列はシーケンスであり、同じタイプのインスタンスが固定数含まれています。

配列型を作成するための推奨される方法は、データ型に正の整数を乗算することです。

TenPointsArrayType = POINT * 10

これはやや人工的なデータ型の例であり、他のものの中でも特に4つのPOINTを含む構造です。

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = ("x", c_int), ("y", c_int)
...
>>> class MyStruct(Structure):
...     _fields_ = [("a", c_int),
...                 ("b", c_float),
...                 ("point_array", POINT * 4)]
>>>
>>> print(len(MyStruct().point_array))
4
>>>

インスタンスは、クラスを呼び出すことにより、通常の方法で作成されます。

arr = TenPointsArrayType()
for pt in arr:
    print(pt.x, pt.y)

上記のコードは、配列の内容がゼロに初期化されているため、一連の0 0行を出力します。

正しいタイプのイニシャライザーも指定できます。

>>> from ctypes import *
>>> TenIntegers = c_int * 10
>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> print(ii)
<c_long_Array_10 object at 0x...>
>>> for i in ii: print(i, end=" ")
...
1 2 3 4 5 6 7 8 9 10
>>>

ポインタ

ポインタインスタンスは、 ctypes タイプで pointer()関数を呼び出すことによって作成されます。

>>> from ctypes import *
>>> i = c_int(42)
>>> pi = pointer(i)
>>>

ポインタインスタンスには、ポインタが指すオブジェクト、上記のiオブジェクトを返す contents 属性があります。

>>> pi.contents
c_long(42)
>>>

ctypes にはOOR(元のオブジェクトの戻り値)がないことに注意してください。属性を取得するたびに、新しい同等のオブジェクトが作成されます。

>>> pi.contents is i
False
>>> pi.contents is pi.contents
False
>>>

別の c_int インスタンスをポインターのcontents属性に割り当てると、ポインターはこれが格納されているメモリ位置を指すようになります。

>>> i = c_int(99)
>>> pi.contents = i
>>> pi.contents
c_long(99)
>>>

ポインタインスタンスは、整数でインデックスを付けることもできます。

>>> pi[0]
99
>>>

整数インデックスに割り当てると、ポイントされる値が変更されます。

>>> print(i)
c_long(99)
>>> pi[0] = 22
>>> print(i)
c_long(22)
>>>

0以外のインデックスを使用することもできますが、Cの場合と同様に、何をしているのかを知っている必要があります。任意のメモリ位置にアクセスまたは変更できます。 通常、この機能を使用するのは、C関数からポインターを受け取り、ポインターが実際には単一の項目ではなく配列を指していることを知っている場合のみです。

舞台裏では、 pointer()関数は、単にポインターインスタンスを作成するだけでなく、最初にポインタータイプを作成する必要があります。 これは、 POINTER()関数を使用して実行されます。この関数は、任意の ctypes 型を受け入れ、新しい型を返します。

>>> PI = POINTER(c_int)
>>> PI
<class 'ctypes.LP_c_long'>
>>> PI(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: expected c_long instead of int
>>> PI(c_int(42))
<ctypes.LP_c_long object at 0x...>
>>>

引数なしでポインタ型を呼び出すと、NULLポインタが作成されます。 NULLポインターのブール値はFalseです。

>>> null_ptr = POINTER(c_int)()
>>> print(bool(null_ptr))
False
>>>

ctypes は、ポインターを逆参照するときにNULLをチェックします(ただし、無効な非NULLポインターを逆参照すると、Pythonがクラッシュします)。

>>> null_ptr[0]
Traceback (most recent call last):
    ....
ValueError: NULL pointer access
>>>

>>> null_ptr[0] = 1234
Traceback (most recent call last):
    ....
ValueError: NULL pointer access
>>>

型変換

通常、ctypesは厳密な型チェックを行います。 つまり、関数のargtypesリストにPOINTER(c_int)がある場合、または構造体定義のメンバーフィールドのタイプとしてある場合、まったく同じタイプのインスタンスのみが受け入れられます。 このルールにはいくつかの例外があり、ctypesは他のオブジェクトを受け入れます。 たとえば、ポインタ型の代わりに互換性のある配列インスタンスを渡すことができます。 したがって、POINTER(c_int)の場合、ctypesはc_intの配列を受け入れます。

>>> class Bar(Structure):
...     _fields_ = [("count", c_int), ("values", POINTER(c_int))]
...
>>> bar = Bar()
>>> bar.values = (c_int * 3)(1, 2, 3)
>>> bar.count = 3
>>> for i in range(bar.count):
...     print(bar.values[i])
...
1
2
3
>>>

また、argtypesで関数の引数がポインタ型(POINTER(c_int)など)として明示的に宣言されている場合、指定型のオブジェクト(この場合はc_int)関数に渡すことができます。 この場合、ctypesは必要な byref()変換を自動的に適用します。

POINTERタイプフィールドをNULLに設定するには、Noneを割り当てることができます。

>>> bar.values = None
>>>

互換性のないタイプのインスタンスがある場合があります。 Cでは、あるタイプを別のタイプにキャストできます。 ctypes は、同じように使用できる cast()関数を提供します。 上で定義されたBar構造体は、valuesフィールドにPOINTER(c_int)ポインターまたは c_int 配列を受け入れますが、他のタイプのインスタンスは受け入れません。

>>> bar.values = (c_byte * 4)()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
>>>

このような場合、 cast()関数が便利です。

cast()関数を使用して、ctypesインスタンスを別のctypesデータ型へのポインターにキャストできます。 cast()は、ある種のポインターに変換される、または変換できるctypesオブジェクトと、ctypesポインター型の2つのパラメーターを取ります。 これは、最初の引数と同じメモリブロックを参照する2番目の引数のインスタンスを返します。

>>> a = (c_byte * 4)()
>>> cast(a, POINTER(c_int))
<ctypes.LP_c_long object at ...>
>>>

したがって、 cast()を使用して、Barvaluesフィールドに構造を割り当てることができます。

>>> bar = Bar()
>>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
>>> print(bar.values[0])
0
>>>

不完全なタイプ

不完全な型は、メンバーがまだ指定されていない構造体、共用体、または配列です。 Cでは、これらは後で定義される前方宣言によって指定されます。

struct cell; /* forward declaration */

struct cell {
    char *name;
    struct cell *next;
};

ctypesコードへの簡単な変換は次のようになりますが、機能しません。

>>> class cell(Structure):
...     _fields_ = [("name", c_char_p),
...                 ("next", POINTER(cell))]
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in cell
NameError: name 'cell' is not defined
>>>

新しいclass cellはクラスステートメント自体では使用できないためです。 ctypes では、cellクラスを定義し、後でクラスステートメントの後に_fields_属性を設定できます。

>>> from ctypes import *
>>> class cell(Structure):
...     pass
...
>>> cell._fields_ = [("name", c_char_p),
...                  ("next", POINTER(cell))]
>>>

試してみよう。 cellの2つのインスタンスを作成し、それらを相互にポイントさせ、最後にポインターチェーンを数回たどります。

>>> c1 = cell()
>>> c1.name = b"foo"
>>> c2 = cell()
>>> c2.name = b"bar"
>>> c1.next = pointer(c2)
>>> c2.next = pointer(c1)
>>> p = c1
>>> for i in range(8):
...     print(p.name, end=" ")
...     p = p.next[0]
...
foo bar foo bar foo bar foo bar
>>>

コールバック関数

ctypes を使用すると、Python呼び出し可能オブジェクトからC呼び出し可能関数ポインターを作成できます。 これらは、コールバック関数と呼ばれることもあります。

まず、コールバック関数のクラスを作成する必要があります。 このクラスは、呼び出し規約、戻り値の型、およびこの関数が受け取る引数の数と型を認識しています。

CFUNCTYPE()ファクトリ関数は、cdecl呼び出し規約を使用してコールバック関数の型を作成します。 Windowsでは、 WINFUNCTYPE()ファクトリ関数は、stdcall呼び出し規約を使用してコールバック関数の型を作成します。

これらのファクトリ関数は両方とも、最初の引数として結果タイプを使用して呼び出され、コールバック関数は残りの引数として引数タイプを予期していました。

ここでは、標準Cライブラリのqsort()関数を使用する例を示します。この関数は、コールバック関数を使用してアイテムを並べ替えるために使用されます。 qsort()は、整数の配列をソートするために使用されます。

>>> IntArray5 = c_int * 5
>>> ia = IntArray5(5, 1, 7, 33, 99)
>>> qsort = libc.qsort
>>> qsort.restype = None
>>>

qsort()は、並べ替えるデータへのポインター、データ配列内のアイテムの数、1つのアイテムのサイズ、および比較関数へのポインター、コールバックを使用して呼び出す必要があります。 次に、コールバックはアイテムへの2つのポインターを使用して呼び出され、最初のアイテムが2番目のアイテムよりも小さい場合は負の整数、等しい場合はゼロ、それ以外の場合は正の整数を返す必要があります。

したがって、コールバック関数は整数へのポインタを受け取り、整数を返す必要があります。 まず、コールバック関数のtypeを作成します。

>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
>>>

開始するには、渡される値を示す簡単なコールバックを次に示します。

>>> def py_cmp_func(a, b):
...     print("py_cmp_func", a[0], b[0])
...     return 0
...
>>> cmp_func = CMPFUNC(py_cmp_func)
>>>

結果:

>>> qsort(ia, len(ia), sizeof(c_int), cmp_func)  
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 5 7
py_cmp_func 1 7
>>>

これで、実際に2つの項目を比較して、有用な結果を返すことができます。

>>> def py_cmp_func(a, b):
...     print("py_cmp_func", a[0], b[0])
...     return a[0] - b[0]
...
>>>
>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) 
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>

簡単に確認できるように、配列は次のように並べ替えられています。

>>> for i in ia: print(i, end=" ")
...
1 5 7 33 99
>>>

関数ファクトリはデコレータファクトリとして使用できるため、次のように記述した方がよいでしょう。

>>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
... def py_cmp_func(a, b):
...     print("py_cmp_func", a[0], b[0])
...     return a[0] - b[0]
...
>>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
py_cmp_func 5 1
py_cmp_func 33 99
py_cmp_func 7 33
py_cmp_func 1 7
py_cmp_func 5 7
>>>

ノート

CFUNCTYPE()オブジェクトへの参照は、Cコードから使用されている限り保持してください。 ctypes はそうではなく、そうでない場合、それらはガベージコレクションされ、コールバックが行われたときにプログラムをクラッシュさせる可能性があります。

また、コールバック関数がPythonの制御外で作成されたスレッドで呼び出された場合(例: コールバックを呼び出す外部コードによって)、ctypesはすべての呼び出しで新しいダミーのPythonスレッドを作成します。 この動作はほとんどの目的で正しいですが、 threading.local で保存された値は、同じCスレッドから呼び出された場合でも、異なるコールバック間で not 存続します。


DLLからエクスポートされた値へのアクセス

一部の共有ライブラリは、関数をエクスポートするだけでなく、変数もエクスポートします。 Pythonライブラリ自体の例は、 Py_OptimizeFlag です。これは、指定された -O または -OO フラグに応じて、0、1、または2に設定された整数です。始めるとき。

ctypes は、このタイプのin_dll()クラスメソッドを使用してこのような値にアクセスできます。 pythonapi は、PythonCAPIへのアクセスを提供する事前定義されたシンボルです。

>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
>>> print(opt_flag)
c_long(0)
>>>

インタプリタが -O で開始された場合、サンプルはc_long(1)を印刷し、 -OO が指定された場合はc_long(2)を印刷します。

ポインターの使用法も示す拡張例は、Pythonによってエクスポートされた PyImport_FrozenModules ポインターにアクセスします。

その値のドキュメントを引用する:

このポインターは、 struct _frozen レコードの配列を指すように初期化され、メンバーがすべてNULLまたはゼロである配列で終了します。 フリーズされたモジュールがインポートされると、このテーブルで検索されます。 サードパーティのコードはこれを悪用して、動的に作成された凍結モジュールのコレクションを提供する可能性があります。


したがって、このポインタを操作することも有用であることがわかります。 サンプルサイズを制限するために、このテーブルを ctypes で読み取る方法のみを示します。

>>> from ctypes import *
>>>
>>> class struct_frozen(Structure):
...     _fields_ = [("name", c_char_p),
...                 ("code", POINTER(c_ubyte)),
...                 ("size", c_int)]
...
>>>

struct _frozen データ型を定義したので、テーブルへのポインターを取得できます。

>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
>>>

tablestruct_frozenレコードの配列に対するpointerであるため、反復処理できますが、ポインターにはサイズがないため、ループが終了することを確認する必要があります。 。 遅かれ早かれ、アクセス違反などでクラッシュする可能性があるため、NULLエントリに到達したときにループから抜け出すことをお勧めします。

>>> for item in table:
...     if item.name is None:
...         break
...     print(item.name.decode("ascii"), item.size)
...
_frozen_importlib 31764
_frozen_importlib_external 41499
__hello__ 161
__phello__ -161
__phello__.spam 161
>>>

標準のPythonにフリーズされたモジュールとフリーズされたパッケージ(負のsizeメンバーで示される)があるという事実はよく知られておらず、テストにのみ使用されます。 たとえば、import __hello__で試してみてください。


サプライズ

ctypes には、実際に起こること以外の何かを期待する可能性のあるいくつかのエッジがあります。

次の例を考えてみましょう。

>>> from ctypes import *
>>> class POINT(Structure):
...     _fields_ = ("x", c_int), ("y", c_int)
...
>>> class RECT(Structure):
...     _fields_ = ("a", POINT), ("b", POINT)
...
>>> p1 = POINT(1, 2)
>>> p2 = POINT(3, 4)
>>> rc = RECT(p1, p2)
>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
1 2 3 4
>>> # now swap the two points
>>> rc.a, rc.b = rc.b, rc.a
>>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
3 4 3 4
>>>

うーん。 私たちは確かに最後のステートメントが3 4 1 2を出力することを期待していました。 どうしたの? 上記のrc.a, rc.b = rc.b, rc.a行の手順は次のとおりです。

>>> temp0, temp1 = rc.b, rc.a
>>> rc.a = temp0
>>> rc.b = temp1
>>>

temp0temp1は、上記のrcオブジェクトの内部バッファーを引き続き使用しているオブジェクトであることに注意してください。 したがって、rc.a = temp0を実行すると、temp0のバッファ内容がrcのバッファにコピーされます。 これにより、temp1の内容が変更されます。 したがって、最後の割り当てrc.b = temp1は、期待される効果がありません。

Structure、Unions、およびArraysからサブオブジェクトを取得しても、サブオブジェクトはコピーされません。代わりに、ルートオブジェクトの基になるバッファにアクセスするラッパーオブジェクトが取得されます。

予想とは異なる動作をする可能性のある別の例は次のとおりです。

>>> s = c_char_p()
>>> s.value = b"abc def ghi"
>>> s.value
b'abc def ghi'
>>> s.value is s.value
False
>>>

ノート

c_char_p からインスタンス化されたオブジェクトは、値をバイトまたは整数にのみ設定できます。


Falseを印刷するのはなぜですか? ctypesインスタンスは、メモリブロックと、メモリの内容にアクセスするいくつかの記述子を含むオブジェクトです。 Pythonオブジェクトをメモリブロックに保存しても、オブジェクト自体は保存されません。代わりに、オブジェクトのcontentsが保存されます。 コンテンツに再度アクセスすると、毎回新しいPythonオブジェクトが作成されます。


可変サイズのデータ型

ctypes は、可変サイズの配列と構造のサポートを提供します。

resize()関数を使用して、既存のctypesオブジェクトのメモリバッファーのサイズを変更できます。 この関数は、オブジェクトを最初の引数として受け取り、要求されたサイズ(バイト単位)を2番目の引数として受け取ります。 メモリブロックをオブジェクトタイプで指定された自然メモリブロックより小さくすることはできません。これを実行しようとすると、 ValueError が発生します。

>>> short_array = (c_short * 4)()
>>> print(sizeof(short_array))
8
>>> resize(short_array, 4)
Traceback (most recent call last):
    ...
ValueError: minimum size is 8
>>> resize(short_array, 32)
>>> sizeof(short_array)
32
>>> sizeof(type(short_array))
8
>>>

これは素晴らしいことですが、この配列に含まれる追加の要素にどのようにアクセスしますか? タイプはまだ4つの要素しか認識していないため、他の要素にアクセスするとエラーが発生します。

>>> short_array[:]
[0, 0, 0, 0]
>>> short_array[7]
Traceback (most recent call last):
    ...
IndexError: invalid index
>>>

ctypes で可変サイズのデータ型を使用する別の方法は、Pythonの動的な性質を使用し、必要なサイズがすでにわかった後で、ケースバイケースでデータ型を(再)定義することです。


ctypesリファレンス

共有ライブラリの検索

コンパイル言語でプログラミングする場合、プログラムのコンパイル/リンク時、およびプログラムの実行時に共有ライブラリにアクセスします。

find_library()関数の目的は、コンパイラーまたはランタイムローダーが行うのと同様の方法でライブラリーを見つけることです(共有ライブラリーのいくつかのバージョンがあるプラットフォームでは、最新のものをロードする必要があります)が、ctypesライブラリーはローダーは、プログラムが実行されたときのように動作し、ランタイムローダーを直接呼び出します。

ctypes.utilモジュールは、ロードするライブラリを決定するのに役立つ関数を提供します。

ctypes.util.find_library(name)
ライブラリを見つけて、パス名を返してみてください。 name は、 lib のようなプレフィックス、.so.dylibのようなサフィックス、またはバージョン番号のないライブラリ名です(これはposixに使用される形式です)リンカーオプション-l)。 ライブラリが見つからない場合は、Noneを返します。

正確な機能はシステムによって異なります。

Linuxでは、find_library()は外部プログラム(/sbin/ldconfiggccobjdumpld)を実行してライブラリファイルを見つけようとします。 ライブラリファイルのファイル名を返します。

バージョン3.6で変更: Linuxでは、他の方法でライブラリが見つからない場合、ライブラリを検索するときに環境変数LD_LIBRARY_PATHの値が使用されます。


ここではいくつかの例を示します。

>>> from ctypes.util import find_library
>>> find_library("m")
'libm.so.6'
>>> find_library("c")
'libc.so.6'
>>> find_library("bz2")
'libbz2.so.1.0'
>>>

macOSでは、find_library()は、ライブラリを見つけるためにいくつかの事前定義された命名スキームとパスを試行し、成功した場合は完全なパス名を返します。

>>> from ctypes.util import find_library
>>> find_library("c")
'/usr/lib/libc.dylib'
>>> find_library("m")
'/usr/lib/libm.dylib'
>>> find_library("bz2")
'/usr/lib/libbz2.dylib'
>>> find_library("AGL")
'/System/Library/Frameworks/AGL.framework/AGL'
>>>

Windowsでは、find_library()はシステム検索パスに沿って検索し、絶対パス名を返しますが、事前定義された命名スキームがないため、find_library("c")のような呼び出しは失敗し、Noneを返します。

共有ライブラリを ctypes でラップする場合は、開発時に共有ライブラリ名を決定し、find_library()を使用する代わりに、それをラッパーモジュールにハードコーディングする方が可能性があります。実行時にライブラリを検索します。


共有ライブラリの読み込み

共有ライブラリをPythonプロセスにロードする方法はいくつかあります。 1つの方法は、次のクラスのいずれかをインスタンス化することです。

class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)

このクラスのインスタンスは、ロードされた共有ライブラリを表します。 これらのライブラリの関数は、標準のC呼び出し規約を使用しており、 int を返すと想定されています。

Windowsでは、DLL名が存在していても、 CDLL インスタンスの作成に失敗する場合があります。 ロードされたDLLの依存DLLが見つからない場合、 OSError エラーがメッセージ「[WinError126]指定されたモジュールが見つかりませんでした」で発生します。このエラーメッセージはWindows APIはこの情報を返さないため、不足しているDLLの名前が含まれていないため、このエラーの診断が困難になります。 このエラーを解決し、どのDLLが見つからないかを判断するには、依存するDLLのリストを見つけ、Windowsのデバッグおよびトレースツールを使用して、どのDLLが見つからないかを判断する必要があります。

も参照してください

MicrosoftDUMPBINツール –DLLの依存関係を見つけるためのツール。


class ctypes.OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)

Windowsのみ:このクラスのインスタンスはロードされた共有ライブラリを表し、これらのライブラリの関数はstdcall呼び出し規約を使用し、Windows固有の HRESULT コードを返すと想定されています。 HRESULT 値には、関数呼び出しが失敗したか成功したかを指定する情報と、追加のエラーコードが含まれています。 戻り値が失敗を示している場合、 OSError が自動的に発生します。

バージョン3.3で変更: WindowsError が発生していました。

class ctypes.WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)

Windowsのみ:このクラスのインスタンスはロードされた共有ライブラリを表し、これらのライブラリの関数はstdcall呼び出し規約を使用し、デフォルトで int を返すと想定されています。

Windows CEでは、標準の呼び出し規約のみが使用されます。便宜上、 WinDLL および OleDLL は、このプラットフォームの標準の呼び出し規約を使用します。

Python グローバルインタープリターロックは、これらのライブラリによってエクスポートされた関数を呼び出す前に解放され、後で再取得されます。

class ctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)

このクラスのインスタンスは CDLL インスタンスのように動作しますが、Python GILは関数呼び出し中に解放されず、関数実行後にPythonエラーフラグがチェックされます。 エラーフラグが設定されている場合、Python例外が発生します。

したがって、これはPython Capi関数を直接呼び出す場合にのみ役立ちます。

これらのクラスはすべて、共有ライブラリのパス名である少なくとも1つの引数を指定して呼び出すことでインスタンス化できます。 すでにロードされている共有ライブラリへの既存のハンドルがある場合は、handleという名前のパラメーターとして渡すことができます。それ以外の場合は、基盤となるプラットフォームdlopenまたはLoadLibrary関数を使用してロードします。ライブラリをプロセスに組み込み、それを処理します。

mode パラメーターを使用して、ライブラリーのロード方法を指定できます。 詳細については、 dlopen(3)のマンページを参照してください。 Windowsでは、モードは無視されます。 posixシステムでは、RTLD_NOWは常に追加され、構成できません。

use_errno パラメーターをtrueに設定すると、システム errno エラー番号に安全な方法でアクセスできるctypesメカニズムが有効になります。 ctypes は、システムの errno 変数のスレッドローカルコピーを維持します。 use_errno=Trueで作成された外部関数を呼び出し、関数呼び出しがctypesプライベートコピーと交換される前に errno 値を呼び出すと、関数呼び出しの直後に同じことが起こります。

関数 ctypes.get_errno()はctypesプライベートコピーの値を返し、関数 ctypes.set_errno()はctypesプライベートコピーを新しい値に変更して以前の値を返します。

use_last_error パラメーターをtrueに設定すると、 GetLastError()およびSetLastError() WindowsAPI関数によって管理されるWindowsエラーコードに対して同じメカニズムが有効になります。 ctypes.get_last_error()および ctypes.set_last_error()は、Windowsエラーコードのctypesプライベートコピーを要求および変更するために使用されます。

winmode パラメーターは、ライブラリのロード方法を指定するためにWindowsで使用されます( mode は無視されるため)。 Win32 API LoadLibraryExフラグパラメータに有効な任意の値を取ります。 省略した場合、デフォルトでは、DLLハイジャックなどの問題を回避するために最も安全なDLLロードをもたらすフラグが使用されます。 DLLにフルパスを渡すことは、正しいライブラリと依存関係がロードされていることを確認するための最も安全な方法です。

バージョン3.8で変更: winmode パラメーターが追加されました。


ctypes.RTLD_GLOBAL
モードパラメーターとして使用するフラグ。 このフラグが使用できないプラットフォームでは、整数ゼロとして定義されます。
ctypes.RTLD_LOCAL
モードパラメーターとして使用するフラグ。 これが利用できないプラットフォームでは、 RTLD_GLOBAL と同じです。
ctypes.DEFAULT_MODE
共有ライブラリのロードに使用されるデフォルトモード。 OSX 10.3では、これは RTLD_GLOBAL です。それ以外の場合は、 RTLD_LOCAL と同じです。

これらのクラスのインスタンスには、パブリックメソッドがありません。 共有ライブラリによってエクスポートされた関数には、属性またはインデックスとしてアクセスできます。 属性を介して関数にアクセスすると結果がキャッシュされるため、関数にアクセスすると毎回同じオブジェクトが返されることに注意してください。 一方、インデックスを介してアクセスすると、毎回新しいオブジェクトが返されます。

>>> from ctypes import CDLL
>>> libc = CDLL("libc.so.6")  # On Linux
>>> libc.time == libc.time
True
>>> libc['time'] == libc['time']
False

次のパブリック属性を使用できます。それらの名前は、エクスポートされた関数名と衝突しないようにアンダースコアで始まります。

PyDLL._handle
ライブラリへのアクセスに使用されるシステムハンドル。
PyDLL._name
コンストラクターで渡されたライブラリーの名前。

共有ライブラリは、[X108X] メソッドを呼び出すか、ローダーの属性としてライブラリを取得することにより、 LibraryLoader クラスのインスタンスであるプレハブオブジェクトの1つを使用してロードすることもできます。実例。

class ctypes.LibraryLoader(dlltype)

共有ライブラリをロードするクラス。 dlltype は、 CDLLPyDLLWinDLL 、または OleDLL タイプのいずれかである必要があります。

__getattr__()には特別な動作があります。ライブラリローダーインスタンスの属性として共有ライブラリにアクセスすることで、共有ライブラリをロードできます。 結果はキャッシュされるため、属性アクセスを繰り返すと、毎回同じライブラリが返されます。

LoadLibrary(name)

共有ライブラリをプロセスにロードして返します。 このメソッドは常にライブラリの新しいインスタンスを返します。

これらのプレハブライブラリローダーが利用可能です:

ctypes.cdll
CDLL インスタンスを作成します。
ctypes.windll
Windowsのみ: WinDLL インスタンスを作成します。
ctypes.oledll
Windowsのみ: OleDLL インスタンスを作成します。
ctypes.pydll
PyDLL インスタンスを作成します。

C Python APIに直接アクセスするために、すぐに使用できるPython共有ライブラリオブジェクトを利用できます。

ctypes.pythonapi
Python CAPI関数を属性として公開する PyDLL のインスタンス。 これらの関数はすべてC int を返すと想定されていることに注意してください。これはもちろん常に真実であるとは限らないため、これらの関数を使用するには正しいrestype属性を割り当てる必要があります。


外国の機能

前のセクションで説明したように、外部関数は、ロードされた共有ライブラリの属性としてアクセスできます。 この方法で作成された関数オブジェクトは、デフォルトで任意の数の引数を受け入れ、任意のctypesデータインスタンスを引数として受け入れ、ライブラリローダーによって指定されたデフォルトの結果タイプを返します。 これらはプライベートクラスのインスタンスです。

class ctypes._FuncPtr

C呼び出し可能外部関数の基本クラス。

外部関数のインスタンスもC互換のデータ型です。 それらはC関数ポインタを表します。

この動作は、外部関数オブジェクトの特別な属性に割り当てることでカスタマイズできます。

restype

ctypesタイプを割り当てて、外部関数の結果タイプを指定します。 void にはNoneを使用します。これは、何も返さない関数です。

ctypes型ではない呼び出し可能なPythonオブジェクトを割り当てることができます。この場合、関数はC int を返すと想定され、呼び出し可能なものはこの整数で呼び出され、さらなる処理またはエラーが可能になります。チェック中。 これを使用することは非推奨です。より柔軟な後処理またはエラーチェックのために、ctypesデータ型を restype として使用し、callableを errcheck 属性に割り当てます。

argtypes

ctypesタイプのタプルを割り当てて、関数が受け入れる引数タイプを指定します。 stdcall呼び出し規約を使用する関数は、このタプルの長さと同じ数の引数でのみ呼び出すことができます。 C呼び出し規約を使用する関数は、追加の不特定の引数も受け入れます。

外部関数が呼び出されると、各実際の引数が argtypes タプル内のアイテムのfrom_param()クラスメソッドに渡されます。このメソッドを使用すると、実際の引数を外部関数が使用するオブジェクトに適合させることができます。を受け入れます。 たとえば、 argtypes タプルの c_char_p アイテムは、ctypes変換ルールを使用して、引数として渡された文字列をバイトオブジェクトに変換します。

New:ctypesタイプではないargtypesにアイテムを配置できるようになりましたが、各アイテムには、引数として使用可能な値(整数、文字列、ctypesインスタンス)を返すfrom_param()メソッドが必要です。 これにより、カスタムオブジェクトを関数パラメーターとして適合させることができるアダプターを定義できます。

errcheck

Python関数または別の呼び出し可能オブジェクトをこの属性に割り当てます。 呼び出し可能オブジェクトは、3つ以上の引数で呼び出されます。

callable(result, func, arguments)

result は、restype属性で指定されているように、外部関数が返すものです。

func は外部関数オブジェクト自体です。これにより、同じ呼び出し可能オブジェクトを再利用して、複数の関数の結果をチェックまたは後処理することができます。

arguments は、関数呼び出しに最初に渡されたパラメーターを含むタプルです。これにより、使用される引数の動作を特殊化できます。

この関数が返すオブジェクトは、外部関数呼び出しから返されますが、結果値を確認して、外部関数呼び出しが失敗した場合に例外を発生させることもできます。

exception ctypes.ArgumentError
この例外は、外部関数呼び出しが渡された引数の1つを変換できない場合に発生します。


関数プロトタイプ

関数プロトタイプをインスタンス化することにより、外部関数を作成することもできます。 関数プロトタイプは、Cの関数プロトタイプに似ています。 それらは、実装を定義せずに関数(戻り型、引数型、呼び出し規約)を記述します。 ファクトリ関数は、関数の目的の結果タイプと引数タイプで呼び出す必要があり、デコレータファクトリとして使用できるため、@wrapper構文を介して関数に適用できます。 例については、コールバック関数を参照してください。

ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)
返された関数プロトタイプは、標準のC呼び出し規約を使用する関数を作成します。 この関数は、呼び出し中にGILを解放します。 use_errno がtrueに設定されている場合、システム errno 変数のctypesプライベートコピーは、呼び出しの前後に実際の errno 値と交換されます。 use_last_error は、Windowsエラーコードに対して同じことを行います。
ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)
Windowsのみ:返された関数プロトタイプは、 WINFUNCTYPE()CFUNCTYPE()と同じであるWindows CEを除いて、stdcall呼び出し規約を使用する関数を作成します。 この関数は、呼び出し中にGILを解放します。 use_errnouse_last_error は上記と同じ意味です。
ctypes.PYFUNCTYPE(restype, *argtypes)
返された関数プロトタイプは、Pythonの呼び出し規約を使用する関数を作成します。 この関数は、呼び出し中にGILを解放しません

これらのファクトリ関数によって作成された関数プロトタイプは、呼び出しのパラメータのタイプと数に応じて、さまざまな方法でインスタンス化できます。

prototype(address)
指定されたアドレスにある外部関数を返します。これは整数でなければなりません。
prototype(callable)
Python callable からC呼び出し可能関数(コールバック関数)を作成します。
prototype(func_spec[, paramflags])
共有ライブラリによってエクスポートされた外部関数を返します。 func_spec は2タプル(name_or_ordinal, library)である必要があります。 最初の項目は、エクスポートされた関数の名前(文字列)、またはエクスポートされた関数の序数(小整数)です。 2番目の項目は共有ライブラリインスタンスです。
prototype(vtbl_index, name[, paramflags[, iid]])

COMメソッドを呼び出す外部関数を返します。 vtbl_index は、仮想関数テーブルへのインデックスであり、小さな非負の整数です。 name はCOMメソッドの名前です。 iid は、拡張エラー報告で使用されるインターフェース識別子へのオプションのポインターです。

COMメソッドは、特別な呼び出し規約を使用します。argtypesタプルで指定されているパラメーターに加えて、最初の引数としてCOMインターフェイスへのポインターが必要です。

オプションの paramflags パラメーターは、上記の機能よりもはるかに多くの機能を備えた外部関数ラッパーを作成します。

paramflags は、argtypesと同じ長さのタプルである必要があります。

このタプルの各項目には、パラメーターに関する詳細情報が含まれています。これは、1つ、2つ、または3つの項目を含むタプルである必要があります。

最初の項目は、パラメーターの方向フラグの組み合わせを含む整数です。

1
関数への入力パラメーターを指定します。
2
出力パラメータ。 外部関数は値を入力します。
4
デフォルトで整数ゼロになる入力パラメーター。


オプションの2番目の項目は、文字列としてのパラメータ名です。 これを指定すると、名前付きパラメーターを使用して外部関数を呼び出すことができます。

オプションの3番目の項目は、このパラメーターのデフォルト値です。


この例は、Windows MessageBoxW関数をラップして、デフォルトのパラメーターと名前付き引数をサポートする方法を示しています。 WindowsヘッダーファイルからのC宣言は次のとおりです。

WINUSERAPI int WINAPI
MessageBoxW(
    HWND hWnd,
    LPCWSTR lpText,
    LPCWSTR lpCaption,
    UINT uType);

ctypes によるラッピングは次のとおりです。

>>> from ctypes import c_int, WINFUNCTYPE, windll
>>> from ctypes.wintypes import HWND, LPCWSTR, UINT
>>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)
>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)
>>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)

MessageBox外部関数は、次の方法で呼び出すことができるようになりました。

>>> MessageBox()
>>> MessageBox(text="Spam, spam, spam")
>>> MessageBox(flags=2, text="foo bar")

2番目の例は、出力パラメーターを示しています。 win32 GetWindowRect関数は、呼び出し元が指定する必要のあるRECT構造体にコピーすることにより、指定されたウィンドウのサイズを取得します。 C宣言は次のとおりです。

WINUSERAPI BOOL WINAPI
GetWindowRect(
     HWND hWnd,
     LPRECT lpRect);

ctypes によるラッピングは次のとおりです。

>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError
>>> from ctypes.wintypes import BOOL, HWND, RECT
>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
>>> paramflags = (1, "hwnd"), (2, "lprect")
>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
>>>

出力パラメーターを持つ関数は、出力パラメーター値が1つある場合は自動的に返し、複数ある場合は出力パラメーター値を含むタプルを返すため、GetWindowRect関数は呼び出されたときにRECTインスタンスを返すようになりました。

出力パラメータをerrcheckプロトコルと組み合わせて、さらに出力処理とエラーチェックを行うことができます。 win32 GetWindowRect api関数はBOOLを返し、成功または失敗を通知します。そのため、この関数はエラーチェックを実行し、api呼び出しが失敗したときに例外を発生させます。

>>> def errcheck(result, func, args):
...     if not result:
...         raise WinError()
...     return args
...
>>> GetWindowRect.errcheck = errcheck
>>>

errcheck関数が受け取った引数タプルを変更せずに返す場合、 ctypes は出力パラメーターに対して行う通常の処理を続行します。 RECTインスタンスの代わりにウィンドウ座標のタプルを返したい場合は、関数内のフィールドを取得して返すことができます。通常の処理は実行されなくなります。

>>> def errcheck(result, func, args):
...     if not result:
...         raise WinError()
...     rc = args[1]
...     return rc.left, rc.top, rc.bottom, rc.right
...
>>> GetWindowRect.errcheck = errcheck
>>>

ユーティリティ機能

ctypes.addressof(obj)
メモリバッファのアドレスを整数として返します。 obj はctypesタイプのインスタンスである必要があります。
ctypes.alignment(obj_or_type)
ctypesタイプの配置要件を返します。 obj_or_type はctypesタイプまたはインスタンスである必要があります。
ctypes.byref(obj[, offset])

obj への軽量ポインタを返します。これはctypesタイプのインスタンスである必要があります。 offset のデフォルトはゼロであり、内部ポインター値に追加される整数である必要があります。

byref(obj, offset)は次のCコードに対応します。

(((char *)&obj) + offset)

返されたオブジェクトは、外部関数呼び出しパラメーターとしてのみ使用できます。 pointer(obj)と同様に動作しますが、構築ははるかに高速です。

ctypes.cast(obj, type)
この関数は、Cのキャスト演算子に似ています。 obj と同じメモリブロックを指す type の新しいインスタンスを返します。 type はポインター型である必要があり、 obj はポインターとして解釈できるオブジェクトである必要があります。
ctypes.create_string_buffer(init_or_size, size=None)

この関数は、可変文字バッファーを作成します。 返されるオブジェクトは、 c_char のctypes配列です。

init_or_size は、配列のサイズを指定する整数、または配列項目を初期化するために使用されるバイトオブジェクトである必要があります。

バイトオブジェクトが最初の引数として指定されている場合、配列の最後の要素がNUL終了文字になるように、バッファーはその長さより1項目大きくなります。 バイトの長さを使用しない場合は、配列のサイズを指定できる2番目の引数として整数を渡すことができます。

ctypes.create_unicode_buffer(init_or_size, size=None)

この関数は、可変のUnicode文字バッファを作成します。 返されるオブジェクトは、 c_wchar のctypes配列です。

init_or_size は、配列のサイズを指定する整数、または配列項目を初期化するために使用される文字列である必要があります。

文字列が最初の引数として指定されている場合、バッファは文字列の長さより1項目大きくなるため、配列の最後の要素はNUL終了文字になります。 文字列の長さを使用しない場合は、配列のサイズを指定できる2番目の引数として整数を渡すことができます。

ctypes.DllCanUnloadNow()
Windowsのみ:この関数は、ctypesを使用してインプロセスCOMサーバーを実装できるようにするフックです。 これは、_ctypes拡張dllがエクスポートするDllCanUnloadNow関数から呼び出されます。
ctypes.DllGetClassObject()
Windowsのみ:この関数は、ctypesを使用してインプロセスCOMサーバーを実装できるようにするフックです。 _ctypes拡張dllがエクスポートするDllGetClassObject関数から呼び出されます。
ctypes.util.find_library(name)

ライブラリを見つけて、パス名を返してみてください。 name は、libのようなプレフィックス、.so.dylibのようなサフィックス、またはバージョン番号(これはposixリンカーに使用される形式です)のないライブラリ名です。オプション-l)。 ライブラリが見つからない場合は、Noneを返します。

正確な機能はシステムによって異なります。

ctypes.util.find_msvcrt()

Windowsのみ:Pythonおよび拡張モジュールで使用されるVCランタイムライブラリのファイル名を返します。 ライブラリーの名前が判別できない場合は、Noneが返されます。

たとえば、free(void *)の呼び出しで拡張モジュールによって割り当てられたメモリを解放する必要がある場合は、メモリを割り当てたのと同じライブラリで関数を使用することが重要です。

ctypes.FormatError([code])
Windowsのみ:エラーコードコードのテキストによる説明を返します。 エラーコードが指定されていない場合、最後のエラーコードは、WindowsAPI関数GetLastErrorを呼び出すことによって使用されます。
ctypes.GetLastError()
Windowsのみ:呼び出し元のスレッドでWindowsによって設定された最後のエラーコードを返します。 この関数は、Windows GetLastError()関数を直接呼び出し、エラーコードのctypes-privateコピーを返しません。
ctypes.get_errno()
呼び出し元のスレッドにあるシステム errno 変数のctypes-privateコピーの現在の値を返します。
ctypes.get_last_error()
Windowsのみ:呼び出し元スレッドのシステムLastError変数のctypes-privateコピーの現在の値を返します。
ctypes.memmove(dst, src, count)
標準のCmemmoveライブラリ関数と同じです。 count バイトを src から dst にコピーします。 dst および src は、ポインターに変換できる整数またはctypesインスタンスである必要があります。
ctypes.memset(dst, c, count)
標準のCmemsetライブラリ関数と同じです。アドレス dst のメモリブロックを値 ccount バイトで埋めます。 dst は、アドレスを指定する整数、またはctypesインスタンスである必要があります。
ctypes.POINTER(type)
このファクトリ関数は、新しいctypesポインタ型を作成して返します。 ポインタ型はキャッシュされて内部で再利用されるため、この関数を繰り返し呼び出すのは安価です。 type はctypesタイプである必要があります。
ctypes.pointer(obj)

この関数は、 obj を指す新しいポインタインスタンスを作成します。 返されるオブジェクトのタイプはPOINTER(type(obj))です。

注:オブジェクトへのポインターを外部関数呼び出しに渡すだけの場合は、はるかに高速なbyref(obj)を使用する必要があります。

ctypes.resize(obj, size)
この関数は、 obj の内部メモリバッファのサイズを変更します。これはctypesタイプのインスタンスである必要があります。 sizeof(type(obj))で指定されているように、バッファをオブジェクトタイプのネイティブサイズより小さくすることはできませんが、バッファを大きくすることはできます。
ctypes.set_errno(value)
呼び出しスレッドのシステム errno 変数のctypes-privateコピーの現在の値を value に設定し、前の値を返します。
ctypes.set_last_error(value)
Windowsのみ:呼び出しスレッドのシステムLastError変数のctypes-privateコピーの現在の値を value に設定し、前の値を返します。
ctypes.sizeof(obj_or_type)
ctypesタイプまたはインスタンスメモリバッファのサイズをバイト単位で返します。 C sizeof演算子と同じです。
ctypes.string_at(address, size=- 1)
この関数は、メモリアドレスアドレスで始まるC文字列をバイトオブジェクトとして返します。 サイズが指定されている場合はサイズとして使用され、指定されていない場合、文字列はゼロで終了していると見なされます。
ctypes.WinError(code=None, descr=None)

Windowsのみ:この関数はおそらくctypesで最悪の名前のものです。 OSErrorのインスタンスを作成します。 code が指定されていない場合、GetLastErrorが呼び出されてエラーコードが判別されます。 descr が指定されていない場合、 FormatError()が呼び出され、エラーのテキストによる説明が取得されます。

バージョン3.3で変更: WindowsError のインスタンスが以前作成されていました。

ctypes.wstring_at(address, size=- 1)
この関数は、メモリアドレスアドレスで始まるワイド文字列を文字列として返します。 size が指定されている場合は、文字列の文字数として使用されます。指定されていない場合、文字列はゼロで終了していると見なされます。


データ型

class ctypes._CData

この非公開クラスは、すべてのctypesデータ型に共通の基本クラスです。 特に、すべてのctypesタイプのインスタンスには、C互換データを保持するメモリブロックが含まれています。 メモリブロックのアドレスは、 addressof()ヘルパー関数によって返されます。 別のインスタンス変数は _objects として公開されています。 これには、メモリブロックにポインタが含まれている場合に備えて存続させる必要がある他のPythonオブジェクトが含まれています。

ctypesデータ型の一般的なメソッド。これらはすべてクラスメソッドです(正確には、 metaclass のメソッドです)。

from_buffer(source[, offset])

このメソッドは、 source オブジェクトのバッファーを共有するctypesインスタンスを返します。 source オブジェクトは、書き込み可能なバッファインターフェイスをサポートしている必要があります。 オプションの offset パラメーターは、ソースバッファーへのオフセットをバイト単位で指定します。 デフォルトはゼロです。 ソースバッファが十分に大きくない場合、 ValueError が発生します。

from_buffer_copy(source[, offset])

このメソッドはctypesインスタンスを作成し、読み取り可能でなければならない source オブジェクトバッファーからバッファーをコピーします。 オプションの offset パラメーターは、ソースバッファーへのオフセットをバイト単位で指定します。 デフォルトはゼロです。 ソースバッファが十分に大きくない場合、 ValueError が発生します。

from_address(address)

このメソッドは、整数でなければならない address で指定されたメモリを使用してctypes型インスタンスを返します。

from_param(obj)

このメソッドは、 obj をctypesタイプに適合させます。 タイプが外部関数のargtypesタプルに存在する場合、外部関数呼び出しで使用される実際のオブジェクトで呼び出されます。 関数呼び出しパラメーターとして使用できるオブジェクトを返す必要があります。

すべてのctypesデータ型には、このクラスメソッドのデフォルトの実装があり、それが型のインスタンスである場合、通常は obj を返します。 一部のタイプは他のオブジェクトも受け入れます。

in_dll(library, name)

このメソッドは、共有ライブラリによってエクスポートされたctypesタイプのインスタンスを返します。 name はデータをエクスポートするシンボルの名前、 library はロードされた共有ライブラリです。

ctypesデータ型の一般的なインスタンス変数:

_b_base_

ctypesデータインスタンスは、含まれているメモリブロックを所有しておらず、代わりにベースオブジェクトのメモリブロックの一部を共有している場合があります。 _b_base_ 読み取り専用メンバーは、メモリブロックを所有するルートctypesオブジェクトです。

_b_needsfree_

この読み取り専用変数は、ctypesデータインスタンスがメモリブロック自体を割り当てた場合はtrue、それ以外の場合はfalseです。

_objects

このメンバーは、Noneか、メモリブロックの内容を有効に保つために存続させる必要のあるPythonオブジェクトを含むディクショナリのいずれかです。 このオブジェクトはデバッグ用にのみ公開されています。 この辞書の内容は絶対に変更しないでください。


基本的なデータ型

class ctypes._SimpleCData

この非公開クラスは、すべての基本的なctypesデータ型の基本クラスです。 基本的なctypesデータ型の共通属性が含まれているため、ここで説明します。 _SimpleCData_CData のサブクラスであるため、メソッドと属性を継承します。 ポインタを含まない、または含まないctypesデータ型をpickle化できるようになりました。

インスタンスには1つの属性があります。

value

この属性には、インスタンスの実際の値が含まれます。 整数型およびポインタ型の場合は整数、文字型の場合は単一文字バイトのオブジェクトまたは文字列、文字型ポインタ型の場合はPythonバイトのオブジェクトまたは文字列です。

value属性がctypesインスタンスから取得されると、通常、毎回新しいオブジェクトが返されます。 ctypes は、元のオブジェクトの戻りを実装しません。常に新しいオブジェクトが構築されます。 同じことが他のすべてのctypesオブジェクトインスタンスにも当てはまります。

基本的なデータ型は、外部関数呼び出しの結果として返される場合、またはたとえば構造体フィールドのメンバーや配列項目を取得することによって返される場合、ネイティブのPython型に透過的に変換されます。 つまり、外部関数のrestypec_char_p の場合、常にPythonバイトオブジェクトを受け取ります。ではなく c_char_p インスタンスを受け取ります。 。

基本的なデータ型のサブクラスは、この動作を継承しませんしません。 したがって、外部関数restypec_void_p のサブクラスである場合、関数呼び出しからこのサブクラスのインスタンスを受け取ります。 もちろん、value属性にアクセスすることで、ポインターの値を取得できます。

これらは基本的なctypesデータ型です。

class ctypes.c_byte
C signed char データ型を表し、値を小整数として解釈します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_char
C char データ型を表し、値を1文字として解釈します。 コンストラクターはオプションの文字列初期化子を受け入れます。文字列の長さは正確に1文字でなければなりません。
class ctypes.c_char_p
ゼロで終了する文字列を指す場合、C char * データ型を表します。 バイナリデータも指す可能性のある一般的な文字ポインタの場合、POINTER(c_char)を使用する必要があります。 コンストラクターは、整数アドレスまたはバイトオブジェクトを受け入れます。
class ctypes.c_double
C double データ型を表します。 コンストラクターは、オプションのfloat初期化子を受け入れます。
class ctypes.c_longdouble
C long double データ型を表します。 コンストラクターは、オプションのfloat初期化子を受け入れます。 sizeof(long double) == sizeof(double)c_double のエイリアスであるプラットフォーム。
class ctypes.c_float
C float データ型を表します。 コンストラクターは、オプションのfloat初期化子を受け入れます。
class ctypes.c_int
C signed int データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。 sizeof(int) == sizeof(long)のプラットフォームでは、 c_long のエイリアスです。
class ctypes.c_int8
C8ビット signed int データ型を表します。 通常、 c_byte のエイリアス。
class ctypes.c_int16
C16ビット signed int データ型を表します。 通常、 c_short のエイリアス。
class ctypes.c_int32
C32ビット signed int データ型を表します。 通常、 c_int のエイリアス。
class ctypes.c_int64
C64ビット signed int データ型を表します。 通常、 c_longlong のエイリアス。
class ctypes.c_long
C signed long データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_longlong
C signed long long データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_short
C 符号付きshort データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_size_t
C size_tデータ型を表します。
class ctypes.c_ssize_t

C ssize_tデータ型を表します。

バージョン3.2の新機能。

class ctypes.c_ubyte
C unsigned char データ型を表し、値を小整数として解釈します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_uint
C unsigned int データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。 sizeof(int) == sizeof(long)c_ulong のエイリアスであるプラットフォーム。
class ctypes.c_uint8
C8ビット unsigned int データ型を表します。 通常、 c_ubyte のエイリアス。
class ctypes.c_uint16
C16ビット unsigned int データ型を表します。 通常、 c_ushort のエイリアス。
class ctypes.c_uint32
C32ビット unsigned int データ型を表します。 通常、 c_uint のエイリアス。
class ctypes.c_uint64
C64ビット unsigned int データ型を表します。 通常、 c_ulonglong のエイリアス。
class ctypes.c_ulong
C unsigned long データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_ulonglong
C unsigned long long データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_ushort
C unsigned short データ型を表します。 コンストラクターは、オプションの整数初期化子を受け入れます。 オーバーフローチェックは行われません。
class ctypes.c_void_p
C void * タイプを表します。 値は整数として表されます。 コンストラクターは、オプションの整数初期化子を受け入れます。
class ctypes.c_wchar
C wchar_tデータ型を表し、値を1文字のUnicode文字列として解釈します。 コンストラクターはオプションの文字列初期化子を受け入れます。文字列の長さは正確に1文字でなければなりません。
class ctypes.c_wchar_p
C wchar_t * データ型を表します。これは、ゼロで終了するワイド文字ストリングへのポインターである必要があります。 コンストラクターは、整数アドレスまたは文字列を受け入れます。
class ctypes.c_bool
C bool データ型を表します(より正確には、C99の _Bool )。 その値はTrueまたはFalseであり、コンストラクターは真理値を持つすべてのオブジェクトを受け入れます。
class ctypes.HRESULT
Windowsのみ:HRESULT値を表します。これには、関数またはメソッド呼び出しの成功またはエラー情報が含まれます。
class ctypes.py_object
C PyObject * データ型を表します。 引数なしでこれを呼び出すと、NULL PyObject * ポインターが作成されます。

ctypes.wintypesモジュールは、HWNDWPARAMDWORDなど、他のWindows固有のデータ型を提供します。 MSGRECTのようないくつかの便利な構造も定義されています。


構造化データ型

class ctypes.Union(*args, **kw)
ネイティブバイトオーダーのユニオンの抽象基本クラス。
class ctypes.BigEndianStructure(*args, **kw)
ビッグエンディアンバイトオーダーの構造体の抽象基本クラス。
class ctypes.LittleEndianStructure(*args, **kw)
リトルエンディアンバイトオーダーの構造体の抽象基本クラス。

非ネイティブバイトオーダーの構造体には、ポインター型フィールド、またはポインター型フィールドを含むその他のデータ型を含めることはできません。

class ctypes.Structure(*args, **kw)

native バイトオーダーの構造体の抽象基本クラス。

具体的な構造体と共用体の型は、これらの型の1つをサブクラス化して作成し、少なくとも _fields_ クラス変数を定義する必要があります。 ctypes は、直接属性アクセスによるフィールドの読み取りと書き込みを可能にする記述子を作成します。 これらは

_fields_

構造フィールドを定義するシーケンス。 アイテムは2タプルまたは3タプルである必要があります。 最初の項目はフィールドの名前であり、2番目の項目はフィールドのタイプを指定します。 任意のctypesデータ型にすることができます。

c_int のような整数型フィールドの場合、3番目のオプション項目を指定できます。 フィールドのビット幅を定義する小さな正の整数である必要があります。

フィールド名は、1つの構造体または共用体内で一意である必要があります。 これはチェックされていません。名前が繰り返される場合、アクセスできるフィールドは1つだけです。

_fields_ クラス変数 after をStructureサブクラスを定義するクラスステートメントで定義することができます。これにより、直接または間接的に自身を参照するデータ型を作成できます。

class List(Structure):
    pass
List._fields_ = [("pnext", POINTER(List)),
                 ...
                ]

ただし、 _fields_ クラス変数は、型を最初に使用する前に定義する必要があります(インスタンスが作成され、 sizeof()が呼び出されるなど)。 後で _fields_ クラス変数に割り当てると、AttributeErrorが発生します。

構造タイプのサブサブクラスを定義することができます。これらは、基本クラスのフィールドに加えて、サブサブクラスで定義されている _fields_ を継承します。

_pack_

インスタンス内の構造フィールドの配置をオーバーライドできるようにするオプションの小整数。 _pack_ は、 _fields_ が割り当てられているときにすでに定義されている必要があります。定義されていない場合、効果はありません。

_anonymous_

名前のない(匿名の)フィールドの名前をリストするオプションのシーケンス。 _anonymous_ は、 _fields_ が割り当てられているときにすでに定義されている必要があります。定義されていない場合、効果はありません。

この変数にリストされるフィールドは、構造体または共用体タイプのフィールドである必要があります。 ctypes は、構造体または共用体フィールドを作成する必要なしに、ネストされたフィールドに直接アクセスできるようにする構造体タイプの記述子を作成します。

タイプの例を次に示します(Windows)。

class _U(Union):
    _fields_ = [("lptdesc", POINTER(TYPEDESC)),
                ("lpadesc", POINTER(ARRAYDESC)),
                ("hreftype", HREFTYPE)]

class TYPEDESC(Structure):
    _anonymous_ = ("u",)
    _fields_ = [("u", _U),
                ("vt", VARTYPE)]

TYPEDESC構造体はCOMデータ型を記述し、vtフィールドはユニオンフィールドのどれが有効であるかを指定します。 uフィールドは匿名フィールドとして定義されているため、TYPEDESCインスタンスから直接メンバーにアクセスできるようになりました。 td.lptdesctd.u.lptdescは同等ですが、一時的なユニオンインスタンスを作成する必要がないため、前者の方が高速です。

td = TYPEDESC()
td.vt = VT_PTR
td.lptdesc = POINTER(some_type)
td.u.lptdesc = POINTER(some_type)

構造体のサブサブクラスを定義することが可能であり、それらは基本クラスのフィールドを継承します。 サブクラス定義に個別の _fields_ 変数がある場合、これで指定されたフィールドは基本クラスのフィールドに追加されます。

構造体コンストラクターと共用体コンストラクターは、位置引数とキーワード引数の両方を受け入れます。 位置引数は、 _fields_ に表示されるのと同じ順序でメンバーフィールドを初期化するために使用されます。 コンストラクターのキーワード引数は属性割り当てとして解釈されるため、 _fields_ を同じ名前で初期化するか、 _fields_ に存在しない名前の新しい属性を作成します。


配列とポインタ

class ctypes.Array(*args)

配列の抽象基本クラス。

具体的な配列型を作成するための推奨される方法は、 ctypes データ型に正の整数を乗算することです。 または、このタイプをサブクラス化して、 _length_ および _type_ クラス変数を定義することもできます。 配列要素は、標準の添え字およびスライスアクセスを使用して読み取りおよび書き込みできます。 スライス読み取りの場合、結果のオブジェクトはではなくそれ自体が配列です。

_length_

配列内の要素の数を指定する正の整数。 範囲外の添え字は、 IndexError になります。 len()によって返されます。

_type_

配列内の各要素のタイプを指定します。

配列サブクラスコンストラクターは、要素を順番に初期化するために使用される位置引数を受け入れます。

class ctypes._Pointer

ポインタのプライベートな抽象基本クラス。

具体的なポインタ型は、ポイントされる型で POINTER()を呼び出すことによって作成されます。 これは pointer()によって自動的に行われます。

ポインタが配列を指している場合、その要素は、標準の添え字およびスライスアクセスを使用して読み書きできます。 ポインタオブジェクトにはサイズがないため、 len()TypeError を発生させます。 負の添え字は(Cのように)ポインタののメモリから読み取られ、範囲外の添え字はおそらくアクセス違反でクラッシュします(運が良ければ)。

_type_

指すタイプを指定します。

contents

ポインタが指すオブジェクトを返します。 この属性に割り当てると、割り当てられたオブジェクトを指すようにポインタが変更されます。