2016-10-29 10 views
1

私はこの時点で何時間もインターネットを検索しました。誰もが、どのように構造体にPython関数から返された名前付きタプルを解析するか、またはちょうど別の変数に知っていますか?私が問題を抱えている部分は、返されたポインタからデータを取り出すことです。私はPyObject_CallFunction()呼び出しを使用してC++に埋め込まれたPython関数を呼び出しています。返されたデータにPyObject *を渡すと、何をすべきか分かりません。Python NamedTuple to C++ Struct

私は参照のためにPython 2.7を使用しています。

編集:私はPythonとC++の両方でやろうとしていた機能をすべてPythonに移行しました。近い将来、この質問のコメントに示唆されている戦略の試行について、私は更新する予定です。

+0

namedtupleは組み込み関数ではないため、変換に問題が発生することがあります。 namedtupleを最初に(Pythonレベルから)タプルに変換してから、C++拡張モジュールで 'PyArg_ParseTuple'を使用してみてください。 – thorhunter

+0

@thorhunter私はそのショットを与えるでしょう。 PyArg_ParseTupleのドキュメントを読んで、各パーツにアクセスする方法についてちょっと混乱しました。 Pythonが値を格納するために使用したバイト数を正確に知る必要がありますか? – Wired365

+0

いいえ、あなたが知る必要があるのは、渡すタプルの構造だけです。 (int、int、string)を返します。そして 'PyArg_ParseTuple(args、" iis "、&int1、&int2、&str);' for 'int int1; int int2; char * str')変数を使ってCの型にバインドすることができます。これはもちろん基本的な例です。 'PyArg_ParseTuple'やその他のPython API要素を使ってもっと多くのことを行うことができます。Python APIを使用して必要な情報(文字列の長さを含む)をPython APIから抜き出すことができます。 //docs.python.org/2.0/ext/parseTuple.html – thorhunter

答えて

1

私は PyObject_CallFunction()呼び出しを使用してC++で埋め込まれたPythonの関数を呼び出していると私は、返されたデータに PyObject *を持っていたら、私は何をすべきかわかりません。

namedtupleはタプル要素を名前付き属性として追加的に公開するタプルサブクラスです。つまり、obj[position]またはobj.attributeのようにデータにアクセスするかどうかを選択できます。後者は一般的に読みやすくなりますが、前者はタプルのアンパックとよく似ています。 Python/Cでは、おそらくタプルとしてアクセスする方が簡単です。なぜなら、コメントに示されているように便利な関数PyArg_ParseTupleを使うことができるからです。

オブジェクトの任意の属性を抽出するには(namedtupleである必要はない)、PyObject_GetAttrStringを呼び出します。記述するオブジェクトを考えると、たとえば、ポイント、などxなどの属性を抽出すると、次のようになります。

PyObject *point = ...; // assume we get a new reference to point 
if (!point) 
    return NULL; 
PyObject *x = PyObject_GetAttrString(point, "x"); 
if (!x) { 
    // obj.x raised, possibly because point is of a different type 
    Py_DECREF(point); 
    return NULL; 
} 
double x_val = PyFloat_AsDouble(x); 
Py_DECREF(x);  // x not used below this line 
if (x_val == --1 && PyErr_Occurred()) { 
    // obj.x is not float or float-like 
    Py_DECREF(point); 
    return NULL; 
} 
Py_DECREF(point); // point not used below this line 

エラーチェックと参照カウントはかなり面倒ですが、それはほとんどガードクラスや、より良いを使用して除去することができBoost.Pythonなどの他の人が作成したクラスを使用しています。

+0

代わりの方法をありがとうございます。なぜ、x_val && PyErr_Ocurred()のif文で同じ内容になっているのか、同じチェックを2回行うのはなぜですか? – Wired365

+0

@ Wired365私は最初に書いたコードも 'y'をフェッチしようとしましたが、エラーチェックと参照カウントをすると長すぎました。余分なコピーを取り除く答えを編集しましたまた、 'throw ...'を 'NULLを返す 'ように変更しました。通常はPython/Cで行いたいと思っています。 (エラーを無視して続行する予定の場合は、 'PyErr_Clear'と' PyErr_ExceptionMatches'を呼び出して、無視したい例外を無視していることを覚えておいてください。 – user4815162342

+0

ああそうです私はそれが何であるかと思ったが、私はあなたを完全に理解していることを確認したかった。明確にしてくれてありがとう! – Wired365

0

namedtupleは、純粋にPythonで実装されています。その完全なソースはcollections.pyで見ることができます。それは非常に短いです。覚えておくべきことは、namedtuple自体が呼び出されたフレームにクラスを作成し、このクラス(このクラスのインスタンスではない)を返す関数であるということです。インスタンスの作成に使用されるのはこの返されたクラスです。ですから、あなたが得るオブジェクトは、個々のインスタンスを渡す場合、C++に渡すものではありません。

C++はコンパイル時にstructの定義を作成します。 namedtupleは、実行時にnamedtupleクラスを作成します。それらをC++構造体にバインドする場合は、PyObjectを使用して、新しく作成されたクラスのインスタンスをC++内に作成し、コンパイル時にstruct要素に割り当てます。または、新しく作成されたクラスのインスタンスをPythonで作成し、C++に渡します。

_asdictメソッド(ビルドするすべてのクラスに対してnamedtupleファクトリメソッドによって提供される)を使用して、それをC++に渡して、実行時定義データをコンパイル時に定義されたデータにバインドすることができます。

実際にC++で大量の作業をしたい場合は、namedtupleを使用する代わりにStructモジュールを使用することもできます。

namedtupleは実際にはPythonのスイス軍のナイフで、Pythonにとどまるデータ用です。それは、名前付きアクセス、名前付きアクセスを提供し、すべての要素も "プロパティ"です(したがって、独自のラムダを書く必要はなく、マップ、フィルタなどで使用できるfgetアクセッサメソッドを持っています)。

DBバインディングのようなものです(実行時にどの列が存在するかわからない場合)。あるフォーマットから別のフォーマットへデータを変換するためには、OrderedDictよりも控えめです。このように使用すると、文字列を処理するオーバーヘッドはdbの実際のアクセス(埋め込み)に比べて何もありません。しかし、計算で使われることになっている構造体の大きな配列にはnamedtupleを使用しません。