ブロガーは、いかなる個人または組織にも、ブロガーのオリジナル記事を転載することを許可していません。オリジナリティへのサポートに感謝します。
ブロガーのリンク
私は世界的に有名な端末メーカーに勤めており、モデムチップの研究開発を担当しています。
5Gの初期には端末データサービス層とコアネットワークの開発を担当し、現在は6Gコンピューティングパワーネットワークの技術標準の研究を主導している。
ブログの内容は主に、
5G/6Gプロトコルの説明
コンピューティングパワーネットワークの説明(クラウドコンピューティング、エッジコンピューティング、エンドコンピューティング)
高度なC言語の説明
Rust言語の説明 です。
記事ディレクトリ
C言語とPythonの相互運用性について詳しく解説
公式ドキュメントの紹介: https://docs.python.org/zh-cn/3/extending/index.html
Python では、一部のシステムの標準ヘッダーに影響を与えるプリプロセッサ定義を定義する場合があるため、標準ヘッダーをインクルードする前にこれらのプリプロセッサー定義をインクルードする必要があります
#include<Python.h>
。また、常に Python.h の前に定義することをお勧めします#define PY_SSIZE_T_CLEAN
。
1. C言語呼び出しPython実装方法
1.1 通話プロセス
- C 言語データを Python 形式に変換します。
- 変換されたデータを使用して、Python インターフェイスへの関数呼び出しを実行します。
- 呼び出しによって返されたデータを Python から C 形式に変換します。
1.2 主要な構造と機能の概要
次の関数を使用して、Python 環境を初期化します。
PyConfig_InitPythonConfig() # 初始化一个PyConfig对象
PyConfig_Read() # 读取当前环境的配置信息
Py_InitializeFromConfig() # 使能客制化的Python环境
重要な構造図の 1 つは、PyConfig
いくつかの主要な属性の意味が次のとおりであることです。
- module_search_paths_set # 次の変数は 1 に設定された場合にのみ有効になります
- module_search_paths #指定された検索パスを追加
1.3 単純な Python ステートメントを実行する
単純な Python ステートメントを実行するには、次の関数を使用します。
# 执行字符串参数中的Python语句
PyRun_SimpleString()
#例如:
PyRun_SimpleString("import sys")
1.4 ファイル内の Python ステートメントを実行する
ファイル内の Python ステートメントを実行するには、次の関数を使用します。
# 执行字符串参数中的Python语句
PyRun_SimpleFile()
# 例如:
FILE *fp = fopen("path/to/main.py", "r")
PyRun_SimpleFile(fp, "path/to/main.py")
1.5 Python モジュールのロードとライブラリ関数の呼び出し
Python モジュールをロードし、モジュール内の関数を呼び出す方法は次のとおりです。
PyImport_ImportModule() # 加载指定的Python模块
PyObject_GetAttrString() # 获取模块中的函数或者成员
PyCallable_Check() # 检测获取的模块对象是否可以调用
PyTuple_New() # 当从C调用Python函数的时候,入参必须使用元组封装,此函数创建一个元组对象
PyObject_CallObject() # 调用Python函数
1.6 C言語のデータ型とPythonのデータ型間の変換
公式 Web サイトの API を参照してください: https://docs.python.org/zh-cn/3/c-api/stable.html
要約された命名規則は次のとおりです。
- Python データ型を C 言語データ型に変換
Py<Python 型>_As<C 言語データ型> - C 言語データ型を Python データ型に変換
Py<Python タイプ>_From<C 言語データ型>
1.7 Python データ オブジェクトの作成と組み込み関数の使用
- Python でデータ型を使用したい場合は、公式 Web サイトで
Py<Python type>_XXXを見つけることができます。 - Python の組み込み関数を使用したい場合は、
Py<Python 基本ライブラリ>_XXXを見つけることができます。
2. PythonはC言語の実装メソッドを呼び出します
2.1 通話プロセス
- C 言語のデータ型を Python 形式に変換します。
- 変換されたデータを使用して、Python インターフェイスへの関数呼び出しを実行します。
- 呼び出しによって返されたデータを Python から C 言語形式に変換します。
2.2 C 関数をモジュールにパッケージ化する
C の変数とメソッドをクラスにカプセル化し (モジュール レベルのメソッドを定義することもできます)、それらをモジュールにパッケージ化して公開する必要があるため、Python で C 関数を使用できるようになります。2 つの主要なデータ構造を以下に紹介します。
-
PyModuleDef
- m_base : 基本クラスです。常に PyModuleDef_HEAD_INIT である必要があります。
- m_name : モジュールの名前
- m_size : 現在は -1 に設定されていますが、一部の高度な使用法ではこのパラメータが使用されます。
- m_methods : モジュールメソッドのリスト
-
PyMethodDef
- ml_name : Python で認識されるメソッド名
- ml_meth : 対応するC関数名
- ml_flags : 関数にパラメータがあるかどうかを示します
2.3 クラスの定義方法
クラスを定義する重要なデータ型は、PyTypeObject
いくつかのクラス属性がこの型で定義されていることです。
- tp_name : クラスの名前 (形式は modulename.classname です)
- tp_basicsize : スペースを割り当てるために使用されるクラスのサイズ
- tp_itemsize : 静的クラスの場合は 0、動的クラスの場合は 0 以外
- tp_flags : クラスの属性パラメータ。少なくとも Py_TPFLAGS_DEFAULT である必要があります。
- tp_new : クラスのインスタンス化関数
- tp_init : クラスの初期化子
- tp_dealloc : クラスのデストラクター
- tp_members : メンバーリスト
- tp_methods : メソッドリスト(構造はモジュールと同じ)
- tp_getset : 属性の取得および設定関数
メンバー定義を含む構造PyMemberDef
、主要なメンバーの意味:
- name : Python で表示されるメンバー名
- タイプ: メンバータイプ
- offset : 構造体のメンバーのオフセット。offset() 関数を使用して取得します。
属性の get メソッドと set メソッドを定義する構造PyGetSetDef
、その主要メンバーの意味:
- name : Python で認識される属性の名前
- get、set : 対応する属性の get および set メソッド
2.4 モジュールの主要な機能を定義する
定義したモジュールが Python で呼び出されるとき、PyMODINIT_FUNC PyInit_<moduleName>(void)
関数が呼び出されます。単純な PyInit_(void) 実装プロセスは次のとおりです。
PyType_Ready()
定義された静的クラスを使用してメモリ空間を分類します。PyModule_Create()
作成モジュールを使用します。- 次に、 を使用して
PyModule_AddObject()
、定義したクラスをモジュールに登録します。
詳しいプロセスについては、以下のデモをご覧ください。
2.5 セットアップ スクリプトを構築し、C 言語を so、pyd、およびその他の形式にコンパイルする
# file name 'setup.py'
from distutils.core import setup, Extension
module1 = Extension('moduleName', sources = ['moduleName.c'])
setup (name = 'moduleName'
version = '1.0'
description = 'This is a Demo'
ext_modules = [module1 ])
上記のコードのmoduleName をモジュール名に置き換え、対応する C ファイルをソースに追加します。ヘッダー ファイルを追加する必要はありません。次のコマンドを使用してコンパイルしてインストールします。
python setup.py build
python setup.py install
もちろん、現在では C 言語を呼び出す Python を実装するライブラリが多数あります。
- サイソン
- ちふぃ
- ctypes
- スイグ
3. C言語とPython間の相互運用性の例
3.1 C 言語が Python を呼び出す
デモ.py ファイル
def print_c_point(p)
print(p)
main.c ファイル
#define PY_SSIZE_T_CLEAN
#include <Python.h>
PyStatus init_python(const char *program_name, const wchar_t *additional_search_path)
{
assert(program_name);
PyStatus status;
PyConfig config;
PyConfig_InitPythonConfig(&config);
status = PyConfig_SetBytesString(&config, &config.program_name, program_name);
if(PyStatus_Exception(status)){
goto done;
}
status = PyConfig_Read(&config)
if(PyStatus_Exception(status)){
goto done;
}
if(additional_search_path){
config.module_search_paths_set = 1;
status = PyWideStringList_Append(&config.module_search_paths, additional_search_path);
if(PyStatus_Exception(status)){
goto done;
}
}
status = Py_InitializeFromConfig(&config);
done:
PyConfig_Clear(&config);
return status;
}
int main(int argc, char *argv[])
{
init_python(argv[0], NULL);
PyRun_SimpleString("from time import time, ctime\n"
"print('Today is', ctime(time()))\n");
File *fp = fopen("path/to/demo.py", "r");
PyRun_SimpleFile(fp, "path/to/demo.py");
PyObject *pyModule, *pyFunc;
PyObject *pyArgs, *pyValue;
pyModule = PyImport_ImportModule(demo.py);
if(!pyModule){
PyErr_Print();
goto end;
}
pyFunc = PyObject_GetAttrString(pyModule, print_c_point);
if(!pyFunc){
Py_DECREF(pyModule);
PyErr_Print();
goto end;
}
if(PyCallable_Check(pyFunc)){
pyArgs = PyTuple_New(1);
for(int i=0;i < 1;++i){
pyValue = PyLong_FromLong(3);
if(!pyValue){
Py_DECREF(pyArgs);
PyErr_Print();
goto end;
}
PyTuple_SetItem(pyArgs, i, pyValue);
}
pyValue = PyObject_CallObject(pyFunc, pyArgs);
Py_DECREF(pyArgs);
if(pyValue){
printf("The result is %ld.\n". PyLong_AsLong(pyValue));
Py_DECREF(pyValue);
} else {
PyErr_Print();
goto end;
}
}
Py_DECREF(pyFunc);
Py_DECREF(pyModule);
end:
if(Py_FinalizeEx() < 0)
exit(-1);
return 0;
}
3.2 C言語を呼び出すPython
main.py ファイル
import custom
if '__main__' == __name__:
use_custom("custom module", 1234)
Custom.c ファイル
typedef struct {
PyObject_HEAD
PyObject *user_name;
unsigned int passwd;
} customObject;
static int
custom_clear(customObject *self)
{
Py_CLEAR(self->user_name);
return 0;
}
static void
custom_dealloc(customObject *self)
{
PyObecjt_GC_UnTrack(self);
custom_clear(self);
Py_TYPE(self)->tp_free((PyObject*) self);
}
static PyObject*
custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
customObject *self;
self = (customObject *)type->tp_alloc(type, 0);
if(self != NULL){
self->user_name = PyUnicode_FromString("");
if(self->user_name == NULL){
Py_DECREF(self);
return NULL;
}
self->passwd = 1234;
}
return (PyObject *) self;
}
static int
custom_init(customObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {
"user_name","passwd",NULL};
PyObject *user_name = NULL, *tmp;
if(!PyArg_ParseTupleAndKeywords(args, kwds, "|UkI", kwlist, &user_name, &self->passwd))
return -1;
if(user_name){
tmp = self->user_name;
Py_INCREF(user_name);
self->user_name = user_name;
Py_DECREF(tmp);
}
return 0;
}
static PyMemberDef
custom_members[] = {
{
"passwd", T_ULONG, offset(customObject, passwd), 0, "user password"},
{
NULL}
};
static PyObject *
custom_getusername(customObject *self, void *closure)
{
Py_INCREF(self->user_name);
return self->user_name;
}
static PyObject *
custom_setusername(customObject *self, PyObject *value, void *closure)
{
if(value == NULL) {
PyErr_SetString(PyExc_TypeError, "user name is not NULL");
return -1;
}
if(!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, "user name should string");
return -1;
}
Py_INCREF(value);
Py_CLEAR(self->user_name);
self->user_name = value;
return 0;
}
static int
custom_getpassword(customObject *self, void *closure)
{
PyObject *tmp = PyLong_FromUnsignedLong(self->passwd);
Py_INCREF(tmp);
return tmp;
}
static int
custom_setpassword(customObject *self, PyObject *value, void *closure)
{
if(value == NULL) {
PyErr_SetString(PyExc_TypeError, "user password is not NULL");
return -1;
}
if(!PyLong_Check(value)) {
PyErr_SetString(PyExc_TypeError, "user password should integer");
return -1;
}
self->passwd = PyLong_AsUnsignedLong(value);
return 0;
}
static PyGetSetDef
custom_getsetters[] = {
{
"user_name", (getter)custom_getusername, (setter)custom_setusername, "user name", NULL},
{
"passwd", (getter)custom_getpassword, (setter)custom_setpassword, "user password", NULL},
{
NULL}
};
static PyObject*
custom_printUserInfo(customObject *self, PyObject *Py_UNUSED(ignored))
{
printf("user name is %s and password is %ld.\n",self->user_name,self->passwd);
}
static PyMethodDef custom_methods[] = {
{
"custom_printUserInfo", (PyCFunction) custom_printUserInfo, METH_NOARGS, "print user info"},
{
NULL}
};
static PyTypeObject customType = {
PyVarObject_HEAD_INIT(NULL,0)
.tp_name = "custom.custom",
.tp_doc = PyDoc_STR("custom object"),
.tp_basicsize = sizeof(customObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_new = custom_new,
.tp_init = (initproc)custom_init,
.tp_dealloc = (destructor) custom_dealloc,
.tp_clear = (inquiry) custom_clear,
.tp_members = custom_members,
.tp_methods = custom_methods,
.tp_getset = custom_getsetters,
};
static PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT,
.m_name = "custom",
.m_doc = "example module that creates an extension type",
.m_size = 1
};
PyMODINIT_FUNC
PyInit_custom(void)
{
PyObject *m;
if(PyType_Ready(&customType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if(m == NULL) return NULL;
Py_INCREF(&customType);
if(PyModule_AddObject(m, "custom", (PyObject*)&customType) < 0){
Py_DECREF(&customType);
Py_DECREF(m);
return NULL;
}
return m;
}