산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial programming >> python

Python - C를 사용한 확장 프로그래밍

이전 페이지다음 페이지

C, C++ 또는 Java와 같은 컴파일된 언어를 사용하여 작성하는 모든 코드를 다른 Python 스크립트로 통합하거나 가져올 수 있습니다. 이 코드는 "확장"으로 간주됩니다.

Python 확장 모듈은 일반 C 라이브러리에 불과합니다. Unix 시스템에서 이러한 라이브러리는 일반적으로 .so로 끝납니다. (공유 객체의 경우). Windows 시스템에서는 일반적으로 .dll이 표시됩니다. (동적으로 연결된 라이브러리의 경우).

확장 프로그램 작성을 위한 전제 조건

확장 프로그램 작성을 시작하려면 Python 헤더 파일이 필요합니다.

또한 C 프로그래밍을 사용하여 Python 확장을 작성하려면 C 또는 C++에 대한 지식이 있다고 가정합니다.

Python 확장 프로그램 먼저 살펴보기

Python 확장 모듈을 처음으로 보려면 코드를 네 부분으로 그룹화해야 합니다.

헤더 파일 Python.h

Python.h를 포함해야 합니다. C 소스 파일의 헤더 파일을 사용하면 모듈을 인터프리터에 연결하는 데 사용되는 내부 Python API에 액세스할 수 있습니다.

필요할 수 있는 다른 헤더 앞에 Python.h를 포함해야 합니다. 파이썬에서 호출하려는 함수와 함께 포함을 따라야 합니다.

C 함수

함수의 C 구현 서명은 항상 다음 세 가지 형식 중 하나를 취합니다. -

static PyObject *MyFunction( PyObject *self, PyObject *args );

static PyObject *MyFunctionWithKeywords(PyObject *self,
                                 PyObject *args,
                                 PyObject *kw);

static PyObject *MyFunctionWithNoArgs( PyObject *self );

앞의 각 선언은 Python 객체를 반환합니다. 무효 와 같은 것은 없습니다. 함수가 값을 반환하지 않도록 하려면 Python의 None에 해당하는 C를 반환합니다. 값. Python 헤더는 이를 수행하는 매크로 Py_RETURN_NONE을 정의합니다.

C 함수의 이름은 확장 모듈 외부에서 볼 수 없으므로 원하는 대로 지정할 수 있습니다. 정적으로 정의됩니다. 기능.

C 함수는 일반적으로 여기에 표시된 것처럼 Python 모듈과 함수 이름을 결합하여 이름이 지정됩니다. −

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

이것은 func라는 Python 함수입니다. 모듈 module 내부 . 일반적으로 소스 코드에서 다음에 오는 모듈의 메소드 테이블에 C 함수에 대한 포인터를 놓을 것입니다.

메서드 매핑 테이블

이 메서드 테이블은 PyMethodDef 구조의 간단한 배열입니다. 그 구조는 다음과 같습니다 -

struct PyMethodDef {
   char *ml_name;
   PyCFunction ml_meth;
   int ml_flags;
   char *ml_doc;
};

다음은 이 구조의 구성원에 대한 설명입니다. -

이 테이블은 적절한 구성원에 대해 NULL 및 0 값으로 구성된 센티넬로 종료되어야 합니다.

예시

위에서 정의한 함수에 대해 다음과 같은 메서드 매핑 테이블이 있습니다. -

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

초기화 기능

확장 모듈의 마지막 부분은 초기화 기능입니다. 이 함수는 모듈이 로드될 때 Python 인터프리터에 의해 호출됩니다. 함수 이름은 initModule이어야 합니다. , 여기서 모듈 모듈의 이름입니다.

초기화 함수는 빌드할 라이브러리에서 내보내야 합니다. Python 헤더는 PyMODINIT_FUNC를 정의하여 우리가 컴파일하는 특정 환경에서 발생하도록 적절한 주문을 포함합니다. 함수를 정의할 때 사용하기만 하면 됩니다.

C 초기화 함수는 일반적으로 다음과 같은 전체 구조를 가지고 있습니다 -

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

다음은 Py_InitModule3에 대한 설명입니다. 기능 -

이것을 모두 합치면 다음과 같습니다 -

#include <Python.h>

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

예시

위의 모든 개념을 사용하는 간단한 예 -

#include <Python.h>

static PyObject* helloworld(PyObject* self) {
   return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
   "helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
   {"helloworld", (PyCFunction)helloworld, 
      METH_NOARGS, helloworld_docs},
      {NULL}
};

void inithelloworld(void) {
   Py_InitModule3("helloworld", helloworld_funcs,
                  "Extension module example!");
}

여기 Py_BuildValue 함수는 Python 값을 빌드하는 데 사용됩니다. 위의 코드를 hello.c 파일에 저장합니다. Python 스크립트에서 호출할 이 모듈을 컴파일하고 설치하는 방법을 살펴보겠습니다.

확장 프로그램 빌드 및 설치

distutils 패키지를 사용하면 표준 방식으로 순수 Python 및 확장 모듈 모두의 Python 모듈을 매우 쉽게 배포할 수 있습니다. 모듈은 소스 형식으로 배포되며 일반적으로 setup.py라고 하는 설정 스크립트를 통해 빌드 및 설치됩니다. 다음과 같습니다.

위 모듈의 경우 다음 setup.py 스크립트를 준비해야 합니다. -

from distutils.core import setup, Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld', ['hello.c'])])

이제 필요한 모든 컴파일 및 연결 단계를 수행하는 다음 명령을 올바른 컴파일러 및 링커 명령 및 플래그와 함께 사용하고 결과 동적 라이브러리를 적절한 디렉토리에 복사합니다. -

$ python setup.py install

Unix 기반 시스템에서는 site-packages 디렉토리에 대한 쓰기 권한을 얻기 위해 이 명령을 루트로 실행해야 할 가능성이 큽니다. 일반적으로 Windows에서는 문제가 되지 않습니다.

확장 프로그램 가져오기

확장을 설치하면 다음과 같이 Python 스크립트에서 해당 확장을 가져오고 호출할 수 있습니다. −

#!/usr/bin/python
import helloworld

print helloworld.helloworld()

이것은 다음과 같은 결과를 낳을 것입니다 -

Hello, Python extensions!!

함수 매개변수 전달

인수를 허용하는 함수를 정의할 가능성이 가장 높기 때문에 C 함수에 대해 다른 서명 중 하나를 사용할 수 있습니다. 예를 들어, 몇 가지 매개변수를 허용하는 다음 함수는 다음과 같이 정의됩니다. -

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Parse args and do something interesting here. */
   Py_RETURN_NONE;
}

새 함수에 대한 항목이 포함된 메서드 테이블은 다음과 같습니다. -

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { "func", module_func, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
};

API PyArg_ParseTuple를 사용할 수 있습니다. 함수를 사용하여 C 함수에 전달된 하나의 PyObject 포인터에서 인수를 추출합니다.

PyArg_ParseTuple의 첫 번째 인수는 args 인수입니다. 이것은 파싱할 개체입니다. . 두 번째 인수는 표시될 것으로 예상되는 인수를 설명하는 형식 문자열입니다. 각 인수는 다음과 같이 형식 문자열에서 하나 이상의 문자로 표시됩니다.

static PyObject *module_func(PyObject *self, PyObject *args) {
   int i;
   double d;
   char *s;

   if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
      return NULL;
   }
   
   /* Do something interesting here. */
   Py_RETURN_NONE;
}

모듈의 새 버전을 컴파일하고 가져오면 모든 유형의 인수로 새 함수를 호출할 수 있습니다. −

module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")
module.func(s="three", d=2.0, i=1)

더 많은 변형을 생각해낼 수 있습니다.

PyArg_ParseTuple 기능

다음은 PyArg_ParseTuple의 표준 서명입니다. 기능 -

int PyArg_ParseTuple(PyObject* tuple,char* format,...)

이 함수는 오류의 경우 0을 반환하고 성공의 경우 0이 아닌 값을 반환합니다. 튜플은 C 함수의 두 번째 인수인 PyObject*입니다. 여기 형식 필수 및 선택적 인수를 설명하는 C 문자열입니다.

다음은 PyArg_ParseTuple의 형식 코드 목록입니다. 기능 -

코드 C 유형 의미
c 문자 길이가 1인 Python 문자열은 C 문자가 됩니다.
d 더블 Python float는 C double이 됩니다.
f 플로트 파이썬 부동 소수점은 C 부동 소수점이 됩니다.
int 파이썬 int는 C int가 됩니다.
l Python int는 C long이 됩니다.
L 긴 길이 Python int는 C long long이 됩니다.
PyObject* Python 인수에 대한 NULL이 아닌 차용 참조를 가져옵니다.
s 문자* C char*에 null이 포함되지 않은 Python 문자열입니다.
s# 문자*+int C 주소 및 길이에 대한 모든 Python 문자열.
t# 문자*+int C 주소 및 길이에 대한 읽기 전용 단일 세그먼트 버퍼.
u Py_UNICODE* C에 null이 포함되지 않은 Python 유니코드.
u# Py_UNICODE*+int 모든 Python 유니코드 C 주소 및 길이.
w# 문자*+int 단일 세그먼트 버퍼를 C 주소 및 길이로 읽기/쓰기
z 문자* s와 마찬가지로 None도 허용합니다(C char*를 NULL로 설정).
z# 문자*+int s#와 마찬가지로 None도 허용합니다(C char*를 NULL로 설정).
(...) 에 따라 ... 파이썬 시퀀스는 항목당 하나의 인수로 처리됩니다.
| 다음 인수는 선택 사항입니다.
: 형식 끝, 그 뒤에 오류 메시지의 함수 이름이 옵니다.
; 형식 끝, 전체 오류 메시지 텍스트가 뒤따릅니다.

반환 값

Py_BuildValue PyArg_ParseTuple와 같은 형식 문자열을 받습니다. 하다. 구축 중인 값의 주소를 전달하는 대신 실제 값을 전달합니다. 다음은 추가 기능을 구현하는 방법을 보여주는 예입니다 -

static PyObject *foo_add(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("i", a + b);
}

이것은 Python으로 구현하면 다음과 같습니다. −

def add(a, b):
   return (a + b)

다음과 같이 함수에서 두 개의 값을 반환할 수 있습니다. 이 값은 Python의 목록을 사용하여 캡처됩니다.

static PyObject *foo_add_subtract(PyObject *self, PyObject *args) {
   int a;
   int b;

   if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
      return NULL;
   }
   return Py_BuildValue("ii", a + b, a - b);
}

이것은 Python으로 구현하면 다음과 같습니다. −

def add_subtract(a, b):
   return (a + b, a - b)

Py_BuildValue 기능

다음은 Py_BuildValue의 표준 서명입니다. 기능 -

PyObject* Py_BuildValue(char* format,...)

여기 형식 빌드할 Python 객체를 설명하는 C 문자열입니다. Py_BuildValue의 다음 인수 결과가 빌드되는 C 값입니다. PyObject* 결과는 새로운 참조입니다.

다음 표에는 일반적으로 사용되는 코드 문자열이 나열되어 있으며 그 중 0개 이상이 문자열 형식으로 결합됩니다.

코드 C 유형 의미
c 문자 C 문자는 길이가 1인 파이썬 문자열이 됩니다.
d 더블 C double은 파이썬 float가 됩니다.
f 플로트 C float는 Python float가 됩니다.
int C int는 Python int가 됩니다.
l C long은 Python int가 됩니다.
N PyObject* 파이썬 객체를 전달하고 참조를 훔칩니다.
PyObject* 파이썬 객체를 전달하고 정상적으로 INCREF합니다.
O& 변환+무효* 임의의 변환
s 문자* C 0으로 끝나는 char*는 Python 문자열로, NULL은 None으로
s# 문자*+int C char* 및 길이는 Python 문자열, 또는 NULL은 None입니다.
u Py_UNICODE* C 전체에서 null로 끝나는 문자열을 Python 유니코드로, NULL을 None으로 설정합니다.
u# Py_UNICODE*+int C-와이드 문자열 및 길이는 Python 유니코드로, NULL은 None으로 설정합니다.
w# 문자*+int 단일 세그먼트 버퍼를 C 주소 및 길이로 읽기/쓰기
z 문자* s와 마찬가지로 None도 허용합니다(C char*를 NULL로 설정).
z# 문자*+int s#과 마찬가지로 None도 허용합니다(C char*를 NULL로 설정).
(...) 에 따라 ... C 값에서 Python 튜플을 빌드합니다.
[...] 에 따라 ... C 값에서 Python 목록을 작성합니다.
{...} 에 따라 ... C 값에서 Python 사전을 빌드하고 키와 값을 교대로 사용합니다.

코드 {...}는 짝수개의 C 값(교대로 키와 값)에서 사전을 빌드합니다. 예를 들어, Py_BuildValue("{issi}",23,"zig","zag",42)는 Python의 {23:'zig','zag':42}와 같은 사전을 반환합니다.


python

  1. 파이썬 객체 지향 프로그래밍
  2. Python Print() 문:예제로 인쇄하는 방법
  3. EXAMPLE이 있는 Python String strip() 함수
  4. 예제가 있는 Python 문자열 count()
  5. Python String format() 예제로 설명
  6. 예제가 있는 Python 문자열 find() 메서드
  7. 예제가 있는 Python Lambda 함수
  8. 예제가 있는 Python round() 함수
  9. 예제가 있는 Python map() 함수
  10. 예제가 있는 Python Timeit()