C++enum
を定数のセットではなく実際のエンティティとして SWIG に公開して、Python コードで列挙できるようにすることはできますか?
3 に答える
私は同じ問題に直面しました。SWIGがすぐにC++11をサポートすることを願っていenum class
ます。
SWIGに列挙型を構造体に入れるように説得するハックは次のとおりです。
#ifdef SWIG
%rename(MyEnum) MyEnumNS;
#endif
struct MyEnumNS
{
enum Value { Value1, Value2, Value3 };
};
typedef MyEnumNS::Value MyEnum;
コードでは.cpp
使用する必要がMyEnum::Value1
あり、Pythonコードでは使用する必要がありますMyEnum.Value1
。複雑ではありtypedef
ますが、すべての場所で列挙型を使用する既存のコードを変更する必要がなくなり、SWIG%renameにより、SWIGラッパーで列挙型が同じ名前になります。
Pythonでは、小さなコードで値を列挙できます。
def values(enum):
return [(k,v) for k,v in vars(enum).items() if isinstance(v,int)]
それはきれいではありません、そして私はより良い解決策を見たいです。
ラップする C++ ヘッダーへの侵入が比較的少なく、Python で列挙できるものを作成できます。たとえば、ヘッダー ファイルがあるとします。
#ifndef PYTHON_ENUM
#define PYTHON_ENUM(x) enum x
#endif
PYTHON_ENUM(TestName) {
foo=1,
bar=2
};
PYTHON_ENUM(SomeOtherName) {
woof,
moo
};
C++ では単なる通常の列挙型に展開されますが、Python で列挙型メンバーを公開するヘッダー ファイルとしては十分です。
を使用%typemap(constcode)
すると、enum の Python モジュールに追加のものを挿入できますが、これを行うには enum の名前を知る必要があります。そのための SWIG typeinfo オブジェクトは、あたかもint
. したがって、マクロでちょっとしたハックを使用してPYTHON_ENUM
、列挙型の名前をカスタム typemap に格納します。
%module test
%{
#include "test.h"
%}
%typemap(constcode) int {
PyObject *val = PyInt_FromLong(($type)($value));
SWIG_Python_SetConstant(d, "$1", val);
const char *name = "$typemap(enum_realname,$1_type)";
PyObject *e = PyDict_GetItemString(d, name);
if (!e) PyDict_SetItemString(d, name, e = PyDict_New());
PyDict_SetItemString(e, "$value", val);
}
#define PYTHON_ENUM(x) \
%typemap(enum_realname) int "x"; \
%pythoncode %{ \
x = _test.x\
%} \
enum x
%include "test.h"
これにより、キーと値のペアを持つすべての列挙型の中間モジュールに PyDict が作成されます。%pythoncode
中間モジュールの PyDict を公開モジュールに結び付けるための接着剤もあります。(_test としてハードコードされている以外に、名前で中間モジュールを参照する方法がわかりません - 必要に応じて変更してください)。
これで十分なので、次のように使用できます。
Python 2.7.3 (default, Aug 1 2012, 05:16:07)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> print test.SomeOtherName
{'woof': 0, 'moo': 1}
>>> print test.TestName
{'foo': 1, 'bar': 2}
>>>
typemaps : 型処理はラッパー コード生成の中心であるため、
SWIGではユーザーが完全に定義 (または再定義) できるようになっています。これを行うには、特別な %typemap ディレクティブが使用されます。(SWIG Doc2.0)
タイプマップに関して必要なすべての情報については、これに関する SWIG ドキュメントへのリンクを参照してください。 http://www.swig.org/Doc2.0/Typemaps.html#Typemaps_nn2
タイプマップを使用すると、SWIG に C++ 列挙型を必要な Python オブジェクトに変換するように指示できるはずです。