16

この質問に対する簡単な答えを探していましたが、見つからないようです。Python 2.6/2.7 にまだ含まれていない外部ライブラリには近づかないようにしたいと思います。

次のような 2 つの c ヘッダー ファイルがあります。

//constants_a.h
const double constant1 = 2.25;
const double constant2 = -0.173;
const int constant3 = 13;

...

//constants_b.h
const double constant1 = 123.25;
const double constant2 = -0.12373;
const int constant3 = 14;

...

そして、これらの定数をインポートしたいpythonクラスがあります:

#pythonclass.py
class MyObject(object):
    def __init(self, mode):
        if mode is "a":
            # import from constants_a.h, like:
            # self.constant1 = constant1
            # self.constant2 = constant2
        elif mode is "b":
            # import from constants_b.h, like:
            # self.constant1 = constant1
            # self.constant2 = constant2

...

定数も使用するcコードがあり、これに似ています:

//computations.c
#include <stdio.h>
#include <math.h>
#include "constants_a.h"

// do some calculations, blah blah blah

定数をヘッダー ファイルから Python クラスにインポートするにはどうすればよいですか?

ヘッダー ファイル constants_a.h および constants_b.h の理由は、定数を使用してほとんどの計算を行うために python を使用しているためですが、ある時点で、より最適化された計算を行うために C を使用する必要があります。この時点で、ctypes を使用して c コードを Python にラップしています。定数を更新または変更する必要がある場合に備えて、定数をコードから遠ざけておき、コードもよりクリーンにしたいと考えています。NumPy も使用していることに注意することが役立つかどうかはわかりませんが、それ以外には、他の非標準の Python 拡張機能はありません。また、このプログラムの設計やアーキテクチャに関する提案も受け付けています。

4

4 に答える 4

16

一般に、C ヘッダー ファイルで変数を定義するのはスタイルが悪いです。ヘッダー ファイルは、適切な「.c」ソース コード ファイルの定義を残して、オブジェクトのみを宣言する必要があります。

やりたいことの 1 つはextern const whatever_type_t foo;、C コードのどこかでライブラリ グローバル定数を宣言し、それらを定義 (または「実装」) する (つまり、それらに値を割り当てる) ことです (これは 1 回だけ行うようにしてください)。

とにかく、あなたのやり方は無視ましょう。既に定数を定義し、それらのシンボルを共有オブジェクト ファイル "libfoo.so" で可視化したと仮定してください。Python コードから、libfoo でpi定義されているシンボル にアクセスしたいとします。extern const double pi = 3.1415926;

通常、Python でオブジェクト ファイルをロードするには、次のctypesようにします。

>>> import ctypes
>>> libfoo = ctypes.CDLL("path/to/libfoo.so")

ctypesしかし、その後はthinkslibfoo.piが関数であり、定数データのシンボルではないことがわかります!

>>> libfoo.pi
<_FuncPtr object at 0x1c9c6d0>

その値にアクセスするには、かなり厄介なことをしなければなりません。つまりctypes、関数と思われるものを数値にキャストし直すことです。

>>> pi = ctypes.cast(foo.pi, ctypes.POINTER(ctypes.c_double))
>>> pi.contents.value
3.1415926

C の専門用語では、これは漠然と次のことが起こっていることに対応していconst double piます。

typedef int (*view_anything_as_a_function_t)(void);
view_anyting_as_a_function_t pi_view = &pi;

pi_viewの値を使用するためにポインターをどうしますpiか? としてキャストバックし、const double *逆参照します: *(const double *)(pi_view)

したがって、これはすべて非常に厄介です。何かが足りないのかもしれませんが、これはctypesモジュールの設計によるものだと思います.「外部」データにアクセスするためではなく、主に外部関数呼び出しを行うためのものです。また、ロード可能なライブラリで純粋なデータ シンボルをエクスポートすることは、ほぼ間違いなくまれです。

また、定数が C マクロ定義のみの場合、これは機能しません。一般に、マクロで定義されたデータに外部からアクセスする方法はありません。これらはコンパイル時にマクロ展開され、C コードでマクロ値もエクスポートしない限り、生成されたライブラリ ファイルに目に見えるシンボルは残りません。

于 2013-03-19T15:47:37.330 に答える
12

ファイルから必要な情報を解析するには、正規表現 (reモジュール) を使用することをお勧めします。

完全な C パーサーを構築するのは膨大な作業になりますが、変数のみを使用し、ファイルが適度に単純で予測可能であり、管理されている場合は、何を書く必要があるかは簡単です。

コメントアウトされたコードなどの「落とし穴」のアーティファクトに注意してください。

于 2013-03-08T12:11:01.173 に答える
2

ヘッダーに定数値を格納するのではなく、Python と C プログラムの両方で読み取り可能な何らかの構成ファイルを使用することをお勧めします。たとえば、単純な csv、ini ファイル、または「キー:値」ペアの独自の単純な形式です。また、値の 1 つを変更するたびに C プログラムを再コンパイルする必要はありません :)

于 2013-03-08T12:35:52.127 に答える
1

エミリオに賛成票を投じたいのですが、担当者が不足しています!

他の非標準ライブラリを避けるように要求されましたが、Python コーディングの柔軟性と生の実行速度を提供する Cython (Cython: C-Extensions for Python www.cython.org/) を検討することをお勧めします。 C/C++ でコンパイルされたコードの。

このようにして、すべてに通常の Python を使用できますが、組み込みの C 型を使用してコードの高価な要素を処理できます。次に、Python コードを .c ファイルに変換することもできます (または、外部の C ライブラリ自体をラップするだけです)。その後、バイナリにコンパイルできます。数値ルーチンの場合、最大 10 倍のスピードアップを達成しました。NumPyもそれを使用していると思います。

于 2013-03-08T12:25:06.727 に答える