14.14.1.18 dllからエクスポートされている値へアクセスする

dllは関数だけでなく変数をエクスポートしていることもあります。 Pythonライブラリにある例としてはPy_OptimizeFlag、 起動時の-Oまたは-OOフラグに依存して、 0, 1または2が設定される整数があります。

ctypesは型のin_dllクラスメソッドを使ってこのように 値にアクセスできます。pythonapiはPython C apiへのアクセスできるように するための予め定義されたシンボルです:

>>> 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ポインタにアクセスします。

Pythonドキュメントからの引用すると: このポインタは メンバーがすべてNULLまたはゼロであるレコードを最後に持つ``struct _frozen``レコードの 配列を指すように初期化されます。 フローズン(frozen)モジュールがインポートされたとき、このテーブルから探索されます。 サードパーティ製コードは動的に作成されたフローズンモジュールの集合を提供するためと、 これにいたずらすることができます。

これで、このポインタを操作することが役に立つことを証明できるでしょう。 例の大きさを制限するために、このテーブルを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:
...    print item.name, item.size
...    if item.name is None:
...        break
...
__hello__ 104
__phello__ -104
__phello__.spam 104
None 0
>>>

標準Pythonはフローズンモジュールとフローズンパッケージ(負のサイズのメンバーで 表されています)を持っているという事実はあまり知られておらず、テストにだけ 使われています。例えば、import __hello__を試してみてください。

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。