# 소개

파이썬의 애플리케이션 프로그래머용 인터페이스는 다양한 수준에서 C/C++ 프로그래머에게 파이썬 인터프리터에 대한 접근 방법을 제공합니다. 이 API는 C++에서도 동일하게 사용 가능하지만 간결함을 위해 보통 파이썬/C API 로 불립니다. 파이썬/C API를 사용하는 데에는 근본적으로 다른 두 가지 이유가 있습니다. 첫번째 이유는 특정한 목적을 위해 확장 모듈을 작성하기 위해서입니다; 이 확장 모듈들은 파이썬 인터프리터를 확장하는 C 모듈들입니다. 이것이 아마도 가장 흔한 용도일 것입니다. 두번째 이유는 파이썬을 더 큰 애플리케이션의 컴포넌트로 사용하기 위함입니다. 이 기술은 일반적으로 파이썬을 애플리케이션에 임베딩(embedding) 하는 것을 말합니다.

확장 모듈을 작성하는 것은 비교적 잘 다듬어진 과정으로, “쿡북” 접근법이 잘 통하며 프로세스를 다소 자동화하는 툴들도 존재합니다. 사람들은 파이썬이 존재한 초기부터 다른 애플리케이션에 파이썬을 임베드 해왔으나 파이썬을 임베딩 하는 과정은 확장 모듈을 작성하는 것보다 복잡합니다.

많은 API 함수들은 파이썬을 임베딩하거나 확장하는 것에 무관하게 유용합니다. 더욱이 파이썬을 임베드하는 대부분의 애플리케이션은 커스텀 확장을 제공할 필요성이 있기 때문에 파이썬을 임베드하려고 시도하기 전에 확장을 작성하는 것에 친숙해지는 것이 좋습니다.

## 코딩 표준

CPython 에 포함하기 위해 C 코드를 작성하는 경우에는 PEP 7 에 정의된 지침과 표준을 따라야 합니다. 이 지침은 기여하고 있는 파이썬 버전과 상관없이 적용됩니다. 최종적으로 파이썬에 기여하는 것을 기대하지 않는 이상 이 규칙을 따르는 것은 제삼자 확장 모듈에는 필수가 아닙니다.

## 인클루드 파일

파이썬/C API를 사용하기 위한 모든 함수, 타입 그리고 매크로 정의는 다음 행에 의해 인클루드됩니다.

    #define PY_SSIZE_T_CLEAN
    #include <Python.h>

이는 다음과 같은 표준 헤더를 인클루드하는것을 의미합니다: `<stdio.h>`, `<string.h>`, `<errno.h>`, `<limits.h>`, `<assert.h>` 그리고 `<stdlib.h>` (사용 가능한 경우).

참고

파이썬은 일부 시스템의 표준 헤더에 영향을 미치는 전처리기 정의를 정의할 수 있으므로 표준 헤더를 인클루드하기 전에 `Python.h` 를 인클루드해야 합니다.

`Python.h` 를 인클루드하기 전에 항상 `PY_SSIZE_T_CLEAN` 를 정의하는 것을 권장합니다. 이 매크로에 대한 자세한 사항은 인자 구문 분석과 값 구축 을 참조하십시오.

Python.h로 정의된 사용자에게 공개되는 모든 이름들은 (포함된 표준 헤더로 정의된 것은 제외) `Py` 또는 `_Py` 로 시작하는 이름을 가지고 있습니다. `_Py` 로 시작하는 이름들은 파이썬 구현에 의해 내부적으로 사용되며 확장 개발자들에 의해 사용돠어서는 안됩니다. 구조체 멤버들은 이름에 접두사가 붙지 않습니다.

참고

사용자 코드는 `Py` 또는 `_Py` 로 시작하는 이름들을 정의해서는 안됩니다. 이것은 읽는 사람을 혼란스럽게 하며이러한 접두사가 붙는 추가적인 이름을 정의할수도 있는 향후의 파이썬 버전에 대한 사용자 코드의 이식성을 위태롭게 합니다.

The header files are typically installed with Python. On Unix, these are located in the directories `prefix/include/pythonversion/` and `exec_prefix/include/pythonversion/`, where `prefix` and `exec_prefix` are defined by the corresponding parameters to Python’s configure script and version is `'%d.%d' % sys.version_info[:2]`. On Windows, the headers are installed in `prefix/include`, where `prefix` is the installation directory specified to the installer.

To include the headers, place both directories (if different) on your compiler’s search path for includes. Do not place the parent directories on the search path and then use `#include <pythonX.Y/Python.h>`; this will break on multi-platform builds since the platform independent headers under `prefix` include the platform specific headers from `exec_prefix`.

C++ 사용자들은 파이썬/C API 가 C 만을 사용하여 정의되었어도 헤더 파일들이 `extern "C"` 로 진입점을 제대로 선언한다는 점에 유의해야 합니다. C++ 에서 파이썬/C API 를 사용하기 위해 특별한 조치를 취할 필요는 없습니다.

## 유용한 매크로들

파이썬 헤더 파일에는 몇 가지 유용한 매크로가 정의되어 있습니다. 대부분은 필요한 곳에 가깝게 정의되어 있습니다. (예를 들어 `Py_RETURN_NONE`) 나머지 더 일반적인 유틸리티들은 여기에 정의되어 있습니다. 아래 목록이 전체 목록은 아닙니다.

PyMODINIT_FUNC

  Declare an extension module `PyInit` initialization function. The function return type is PyObject*. The macro declares any special linkage declarations required by the platform, and for C++ declares the function as `extern "C"`.

  The initialization function must be named `PyInit_name`, where name is the name of the module, and should be the only non-`static` item defined in the module file. Example:

      static struct PyModuleDef spam_module = {
          .m_base = PyModuleDef_HEAD_INIT,
          .m_name = "spam",
          ...
      };

      PyMODINIT_FUNC
      PyInit_spam(void)
      {
          return PyModuleDef_Init(&spam_module);
      }

Py_ABS(x)

  `x` 의 절댓값을 반환합니다.

  Added in version 3.3.

Py_ALWAYS_INLINE

  Ask the compiler to always inline a static inline function. The compiler can ignore it and decide to not inline the function.

  It can be used to inline performance critical static inline functions when building Python in debug mode with function inlining disabled. For example, MSC disables function inlining when building in debug mode.

  Marking blindly a static inline function with Py_ALWAYS_INLINE can result in worse performances (due to increased code size for example). The compiler is usually smarter than the developer for the cost/benefit analysis.

  If Python is built in debug mode (if the `Py_DEBUG` macro is defined), the `Py_ALWAYS_INLINE` macro does nothing.

  It must be specified before the function return type. Usage:

      static inline Py_ALWAYS_INLINE int random(void) { return 4; }

  Added in version 3.11.

Py_CHARMASK(c)

  인자는 문자 또는 [-128, 127] 나 [0, 255] 사이의 정수여야 합니다. 이 매크로는 `unsigned char` 로 캐스팅된 `c` 를 반환합니다

Py_DEPRECATED(version)

  폐지(deprecated) 선언에 사용하십시오. 이 매크로는 심볼 이름 앞에 위치해야 합니다

  예제:

      Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);

  버전 3.8에서 변경: MSVC 지원을 추가했습니다.

Py_GETENV(s)

  Like `getenv(s)`, but returns `NULL` if `-E` was passed on the command line (see `PyConfig.use_environment`).

Py_MAX(x, y)

  `x` 와 `y` 사이의 최댓값을 반환합니다.

  Added in version 3.3.

Py_MEMBER_SIZE(type, member)

  (`type`) 구조체의 `member` 의 크기를 바이트로 반환합니다.

  Added in version 3.6.

Py_MIN(x, y)

  `x` 와 `y` 사이의 최솟값을 반환합니다.

  Added in version 3.3.

Py_NO_INLINE

  Disable inlining on a function. For example, it reduces the C stack consumption: useful on LTO+PGO builds which heavily inline code (see bpo-33720).

  Usage:

      Py_NO_INLINE static int random(void) { return 4; }

  Added in version 3.11.

Py_STRINGIFY(x)

  `x` 를 C 문자열로 변환합니다. 예를 들어 `Py_STRINGIFY(123)` 은 `"123"` 을 반환합니다.

  Added in version 3.4.

Py_UNREACHABLE()

  의도적으로 도달할 수 없는 코드 경로가 있을 경우에 이 매크로를 사용하십시오. 예를 들어, `switch` 문에서 가능한 모든 값이 `case` 절에서 다뤄지는 경우에 `default:` 절에서 사용할 수 있습니다. `assert(0)` 또는 `abort()` 대신 사용하십시오.

  릴리즈 모드에서 이 매크로는 컴파일러가 코드를 최적화하는데 도움이 되며 도달할 수 없는 코드에 대한 경고를 방지합니다. 예를 들어, 이 매크로는 릴리즈 모드에서 GCC의 `__builtin_unreachable()` 로 구현됩니다.

  `Py_UNREACHABLE()` 의 용도는 반환하지 않지만 `_Py_NO_RETURN` 을 선언하지 않은 함수를 호출하는 것입니다

  코드 경로가 매우 가능성이 낮지만 예외적인 경우에 도달할 수 있는 경우, 이 매크로를 사용해서는 안됩니다. 예를 들어, 메모리가 부족하거나 시스템 콜이 예상 범위를 벗어나는 값을 반환했을 경우에는 호출자에게 에러를 보고하는 것이 좋습니다. 호출자에게 에러를 보고할 수 없는 경우 `Py_FatalError()` 를 사용할 수 있습니다.

  Added in version 3.7.

Py_UNUSED(arg)

  함수의 미사용 인자에 사용하여 컴파일러 경고를 무시합니다. 예시: `int func(int a, int Py_UNUSED(b)) { return a; }`.

  Added in version 3.4.

PyDoc_STRVAR(name, str)

  독스트링에서 사용 가능한 `name` 이란 이름의 변수를 생성합니다. 파이썬이 독스트링 없이 빌드되었다면 변수의 값은 비어있을 것입니다.

  PEP 7 에 명시된 것처럼 파이썬을 독스트링 없이 빌드하기 위해 `PyDoc_STRVAR` 를 독스트링에 사용하십시오

  예제:

      PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element.");

      static PyMethodDef deque_methods[] = {
          // ...
          {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc},
          // ...
      }

PyDoc_STR(str)

  주어진 문자열에 대한 독스트링을 생성합니다. 독스트링이 비활성화 되어있을 경우엔 빈 문자열을 생성합니다.

  PEP 7 에 명시된 것처럼 독스트링 없이 파이썬을 빌드할 수 있도록 독스트링을 명시할 때 `PyDoc_STR` 을 사용하십시오.

  예제:

      static PyMethodDef pysqlite_row_methods[] = {
          {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
              PyDoc_STR("Returns the keys of the row.")},
          {NULL, NULL}
      };

## 객체, 형 그리고 참조 횟수

Most Python/C API functions have one or more arguments as well as a return value of type PyObject*. This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type `PyObject`, only pointer variables of type PyObject* can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static `PyTypeObject` objects.

모든 파이썬 객체는 (파이썬 정수조차도) 형(type) 과 참조 횟수(reference count) 를 가지고 있습니다. 객체의 형은 객체의 종류를 결정합니다. (예를 들어 정수, 리스트, 또는 사용자 정의 함수 등. 표준형 계층 에 추가적인 형들에 대해 설명되어 있습니다.) 잘 알려진 형에는 객체가 해당 형인지를 확인하는 매크로가 있습니다. 예를 들어 `PyList_Check(a)` 는 a 가 가리키는 객체가 파이썬 리스트일 경우에만 참입니다.

### 참조 횟수

The reference count is important because today’s computers have a finite (and often severely limited) memory size; it counts how many different places there are that have a strong reference to an object. Such a place could be another object, or a global (or static) C variable, or a local variable in some C function. When the last strong reference to an object is released (i.e. its reference count becomes zero), the object is deallocated. If it contains references to other objects, those references are released. Those other objects may be deallocated in turn, if there are no more references to them, and so on. (There’s an obvious problem with objects that reference each other here; for now, the solution is “don’t do that.”)

Reference counts are always manipulated explicitly. The normal way is to use the macro `Py_INCREF()` to take a new reference to an object (i.e. increment its reference count by one), and `Py_DECREF()` to release that reference (i.e. decrement the reference count by one). The `Py_DECREF()` macro is considerably more complex than the incref one, since it must check whether the reference count becomes zero and then cause the object’s deallocator to be called. The deallocator is a function pointer contained in the object’s type structure. The type-specific deallocator takes care of releasing references for other objects contained in the object if this is a compound object type, such as a list, as well as performing any additional finalization that’s needed. There’s no chance that the reference count can overflow; at least as many bits are used to hold the reference count as there are distinct memory locations in virtual memory (assuming `sizeof(Py_ssize_t) >= sizeof(void*)`). Thus, the reference count increment is a simple operation.

It is not necessary to hold a strong reference (i.e. increment the reference count) for every local variable that contains a pointer to an object. In theory, the object’s reference count goes up by one when the variable is made to point to it and it goes down by one when the variable goes out of scope. However, these two cancel each other out, so at the end the reference count hasn’t changed. The only real reason to use the reference count is to prevent the object from being deallocated as long as our variable is pointing to it. If we know that there is at least one other reference to the object that lives at least as long as our variable, there is no need to take a new strong reference (i.e. increment the reference count) temporarily. An important situation where this arises is in objects that are passed as arguments to C functions in an extension module that are called from Python; the call mechanism guarantees to hold a reference to every argument for the duration of the call.

However, a common pitfall is to extract an object from a list and hold on to it for a while without taking a new reference. Some other operation might conceivably remove the object from the list, releasing that reference, and possibly deallocating it. The real danger is that innocent-looking operations may invoke arbitrary Python code which could do this; there is a code path which allows control to flow back to the user from a `Py_DECREF()`, so almost any operation is potentially dangerous.

A safe approach is to always use the generic operations (functions whose name begins with `PyObject_`, `PyNumber_`, `PySequence_` or `PyMapping_`). These operations always create a new strong reference (i.e. increment the reference count) of the object they return. This leaves the caller with the responsibility to call `Py_DECREF()` when they are done with the result; this soon becomes second nature.

#### 참조 횟수 상세

The reference count behavior of functions in the Python/C API is best explained in terms of ownership of references. Ownership pertains to references, never to objects (objects are not owned: they are always shared). “Owning a reference” means being responsible for calling Py_DECREF on it when the reference is no longer needed. Ownership can also be transferred, meaning that the code that receives ownership of the reference then becomes responsible for eventually releasing it by calling `Py_DECREF()` or `Py_XDECREF()` when it’s no longer needed—or passing on this responsibility (usually to its caller). When a function passes ownership of a reference on to its caller, the caller is said to receive a new reference. When no ownership is transferred, the caller is said to borrow the reference. Nothing needs to be done for a borrowed reference.

반대로 호출 함수에게 객체에 대한 참조를 넘길 때는 두가지 가능성이 있습니다: 함수는 객체에 대한 참조를 훔칠 수도, 그러지 않을 수도 있습니다. 참조를 훔치는 것은 함수에 참조를 전달할 때 해당 함수가 전달된 참조를 소유한다고 가정하고 더 이상 책임을 지지 않는다는 것을 의미합니다.

참조를 훔치는 함수는 거의 없습니다. 주목할만한 두가지 예외는 `PyList_SetItem()` 과 `PyTuple_SetItem()` 입니다. 이 두가지 함수는 요소에 대한 참조를 훔칩니다(단, 요소를 넣을 튜플이나 리스트에 대한 참조는 훔치지 않습니다.). 이 함수들은 새로 만들어진 객체들로 튜플이나 리스트를 채우는 일반적인 관행 때문에 참조를 훔치도록 설계되었습니다. 예를 들어, 튜플을 만드는 코드 `(1, 2, "three")` 는 다음과 같을 수 있습니다. (잠시 에러 처리는 잊어버리십시오. 더 좋은 방법으로 코딩하는 방법은 아래에 나와 있습니다.):

    PyObject *t;

    t = PyTuple_New(3);
    PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
    PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
    PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));

여기서 `PyTuple_SetItem()` 는 `PyLong_FromLong()` 가 반환한 참조를 곧바로 훔칩니다. 객체에 대한 참조가 훔쳐져도 계속 객체를 사용하려면 참조를 훔치는 함수를 호출하기 전에 `Py_INCREF()` 를 다른 참조를 가져오는데 사용하십시오.

덧붙이자면, `PyTuple_SetItem()` 은 튜플에 요소를 넣는 유일한 방법입니다. 튜플은 불변 자료형이기 때문에 `PySequence_SetItem()` 과 `PyObject_SetItem()` 는 튜플에 요소를 넣는 것을 거부합니다. `PyTuple_SetItem()` 은 직접 만들고 있는 튜플에만 사용되어야 합니다.

리스트를 채우는 동일한 의미의 코드는 `PyList_New()` 와 `PyList_SetItem()` 을 사용해 만들 수 있습니다.

하지만 실제로는 이렇게 튜플 또는 리스트를 만들고 채우는 경우는 드뭅니다. 일반적인 객체들을 형식 문자열(format string)로 지시되는 C 값으로부터 만들어낼 수 있는 제네릭 함수 `Py_BuildValue()` 가 있습니다. 예룰 들어, 위의 두 블록의 코드를 다음 코드로 대체할 수 있습니다. (에러 검사도 처리합니다.):

    PyObject *tuple, *list;

    tuple = Py_BuildValue("(iis)", 1, 2, "three");
    list = Py_BuildValue("[iis]", 1, 2, "three");

It is much more common to use `PyObject_SetItem()` and friends with items whose references you are only borrowing, like arguments that were passed in to the function you are writing. In that case, their behaviour regarding references is much saner, since you don’t have to take a new reference just so you can give that reference away (“have it be stolen”). For example, this function sets all items of a list (actually, any mutable sequence) to a given item:

    int
    set_all(PyObject *target, PyObject *item)
    {
        Py_ssize_t i, n;

        n = PyObject_Length(target);
        if (n < 0)
            return -1;
        for (i = 0; i < n; i++) {
            PyObject *index = PyLong_FromSsize_t(i);
            if (!index)
                return -1;
            if (PyObject_SetItem(target, index, item) < 0) {
                Py_DECREF(index);
                return -1;
            }
            Py_DECREF(index);
        }
        return 0;
    }

함수 반환 값에 대해서는 상황이 약간 다릅니다. 대부분의 함수에 참조를 전달해도 해당 참조에 대한 소유권 책임이 바뀌진 않지만 객체에 대한 참조를 제공하는 많은 함수는 참조의 소유권을 제공합니다. 이유는 간단합니다. 대부분의 경우에서 반환된 객체는 즉석에서 생성되고 반환된 참조는 객체에 대한 유일한 참조입니다. 따라서 `PyObject_GetItem()` 과 `PySequence_GetItem()` 처럼 객체에 대한 참조를 반환하는 제네릭 함수들은 언제나 새로운 참조를 반환합니다 (호출자가 객체의 소유자가 됩니다).

함수의 의해 반환된 함수를 소유하고 있는지는 어떤 함수를 호출하느냐에 따라 달라진다는 것을 아는 것이 중요합니다. — 깃털 (함수에 인자로 전달된 객체의 형) 은 해당되지 않습니다! 따라서 `PyList_GetItem()` 를 사용하여 리스트에서 항목을 가져오면 참조를 소유하지 않습니다. — 하지만 동일한 인자를 받는 `PySequence_GetItem()` 를 사용하여 리스트에서 항목을 가져온다면 반환된 객체에 대한 참조를 소유하게 됩니다.

다음은 정수 리스트에 있는 항목의 합계를 구하는 함수를 작성하는 방법의 예시입니다. 한 번은 `PyList_GetItem()` 를 사용하고, 한 번은 `PySequence_GetItem()` 을 사용합니다.

    long
    sum_list(PyObject *list)
    {
        Py_ssize_t i, n;
        long total = 0, value;
        PyObject *item;

        n = PyList_Size(list);
        if (n < 0)
            return -1; /* Not a list */
        for (i = 0; i < n; i++) {
            item = PyList_GetItem(list, i); /* Can't fail */
            if (!PyLong_Check(item)) continue; /* Skip non-integers */
            value = PyLong_AsLong(item);
            if (value == -1 && PyErr_Occurred())
                /* Integer too big to fit in a C long, bail out */
                return -1;
            total += value;
        }
        return total;
    }

    long
    sum_sequence(PyObject *sequence)
    {
        Py_ssize_t i, n;
        long total = 0, value;
        PyObject *item;
        n = PySequence_Length(sequence);
        if (n < 0)
            return -1; /* Has no length */
        for (i = 0; i < n; i++) {
            item = PySequence_GetItem(sequence, i);
            if (item == NULL)
                return -1; /* Not a sequence, or other failure */
            if (PyLong_Check(item)) {
                value = PyLong_AsLong(item);
                Py_DECREF(item);
                if (value == -1 && PyErr_Occurred())
                    /* Integer too big to fit in a C long, bail out */
                    return -1;
                total += value;
            }
            else {
                Py_DECREF(item); /* Discard reference ownership */
            }
        }
        return total;
    }

### 형

There are few other data types that play a significant role in the Python/C API; most are simple C types such as int, long, double and char*. A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that use them.

type Py_ssize_t
  Part of the 안정 ABI.

  A signed integral type such that `sizeof(Py_ssize_t) == sizeof(size_t)`. C99 doesn’t define such a thing directly (size_t is an unsigned integral type). See PEP 353 for details. `PY_SSIZE_T_MAX` is the largest positive value of type `Py_ssize_t`.

## 예외

파이썬 프로그래머는 특정한 에러 처리가 필요할 경우에만 에러를 처리하면 됩니다. 처리되지 않은 예외는 사용자에게 전달되는 최상위 인터프리터까지 스택 트레이스백과 함께 자동으로 호출자, 호출자의 호출자 등으로 전파됩니다.

그러나 C 프로그래머들에게 에러 검사는 항상 명시적이어야만 합니다. 파이썬/C API의 모든 함수는 해당 함수의 문서에서 명시하지 않는 한 예외를 발생시킬 수 있습니다. 일반적으로 함수에 에러가 발생하면 함수는 예외를 설정하고 소유하고 있는 모든 객체에 대한 참조를 취소하고 에러 표시기를 반환합니다. 달리 문서화되지 않은 경우 표시기는 함수의 반환 형에 따라 `NULL` 또는 `-1` 입니다. 일부 함수는 에러를 의미하는 거짓과 함께 참/거짓의 불리언 결과를 반환합니다. 아주 일부의 함수는 명시적인 에러 표시기가 없거나 모호한 반환값을 가지며 `PyErr_Occurred()` 를 사용하여 명시적인 점검을 요구합니다. 이런 예외는 항상 명시적으로 문서화됩니다.

예외 상태는 스레드 별 공간에서 관리됩니다. (스레드를 사용하지 않는 프로그램에서는 전역 공간을 사용한다는 말과 같습니다.) 스레드는 예외가 발생했거나, 발생하지 않았거나의 두가지 상태 중 하나일 수 있습니다. 함수 `PyErr_Occurred()` 는 이 상태를 확인하기 위해 사용할 수 있습니다. 해당 함수는 예외가 발생했을 경우 예외 형 객체에 대한 빌린 참조를 반환합니다. 예외가 발생하지 않았을 경우엔 `NULL` 을 반환합니다. 예외 상태를 설정하기 위한 여러가지 함수들이 있습니다: `PyErr_SetString()` 는 예외 상태를 설정하기 위해 가장 보편적인 (가장 일반적인 것은 아니지만) 함수입니다. `PyErr_Clear()` 는 예외 상태를 지웁니다.

전체 예외 상태는 예외 형, 해당 예외 값, 트레이스백이라는 세가지 객체로 구성됩니다. (셋 모두 `NULL` 일 수 있습니다.) 이 세가지 객체는 파이썬의 `sys.exc_info()` 의 결과와 같은 의미를 가지고 있지만 동일하지는 않습니다. 파이썬 객체는 `try` … `except` 문으로 처리되는 마지막 예외를 표현하는 반면 C 수준 예외는 `sys.exc_info()` 와 그 친구들로 예외를 전송하는 파이썬 바이트코드 인터프리터의 메인 루프에 도달할 때까지 C 함수들 간에 전달되는 동안에만 존재합니다.

파이썬 1.5부터 선호되어 온 파이썬 코드에서의 스레드 안전한 예외 상태 접근 방법은 파이썬 코드를 위해 스레드 별 예외 상태를 반환하는 `sys.exc_info()` 함수를 호출하는 것입니다. 또한 예외 상태에 접근하는 양쪽 방법의 의미도 바뀌어 에러를 포착하는 함수가 호출자의 예외 상태를 보존하기 위해 스레드의 예외를 저장하고 복원합니다. 이는 평범해 보이는 함수가 처리중인 예외를 덮어씌우는 것으로 인한 예외 처리 코드의 흔한 버그를 방지합니다. 또한 트레이스백의 스택 프레임에 의하여 참조되는 객체들에 대해 종종 원하지 않은 수명 증가가 일어나는 것을 방지합니다

일반적으로 어떤 작업을 수행하기 위해 다른 함수를 호출하는 함수는 호출된 함수가 예외를 일으켰는지 확인해야만 하며 만약 예외가 일어났다면 호출자에게 예외 상태를 전달해야 합니다. 소유하고 있는 모든 객체에 대한 참조를 버리고 에러 표시기를 반환해야 하지만 다른 예외를 설정해서는 안됩니다. — 방금 일어난 예외를 덮어씌우고 정확한 에러 원인에 대한 중요한 정보를 잃어버리게 됩니다.

A simple example of detecting exceptions and passing them on is shown in the `sum_sequence()` example above. It so happens that this example doesn’t need to clean up any owned references when it detects an error. The following example function shows some error cleanup. First, to remind you why you like Python, we show the equivalent Python code:

    def incr_item(dict, key):
        try:
            item = dict[key]
        except KeyError:
            item = 0
        dict[key] = item + 1

다음은 같은 의미의 웅장한 C 코드입니다:

    int
    incr_item(PyObject *dict, PyObject *key)
    {
        /* Objects all initialized to NULL for Py_XDECREF */
        PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
        int rv = -1; /* Return value initialized to -1 (failure) */

        item = PyObject_GetItem(dict, key);
        if (item == NULL) {
            /* Handle KeyError only: */
            if (!PyErr_ExceptionMatches(PyExc_KeyError))
                goto error;

            /* Clear the error and use zero: */
            PyErr_Clear();
            item = PyLong_FromLong(0L);
            if (item == NULL)
                goto error;
        }
        const_one = PyLong_FromLong(1L);
        if (const_one == NULL)
            goto error;

        incremented_item = PyNumber_Add(item, const_one);
        if (incremented_item == NULL)
            goto error;

        if (PyObject_SetItem(dict, key, incremented_item) < 0)
            goto error;
        rv = 0; /* Success */
        /* Continue with cleanup code */

     error:
        /* Cleanup code, shared by success and failure path */

        /* Use Py_XDECREF() to ignore NULL references */
        Py_XDECREF(item);
        Py_XDECREF(const_one);
        Py_XDECREF(incremented_item);

        return rv; /* -1 for error, 0 for success */
    }

이 예시는 C `goto` 문의 허용된 사용방법을 보여줍니다! 이 예시는 특정한 예외를 처리하기 위한 `PyErr_ExceptionMatches()` 와 `PyErr_Clear()` 의 사용 방법과 `Py_XDECREF()` 를 사용하여 소유하고 있는 `NULL` 일 수도 있는 참조를 삭제하는 방법을 표현합니다. (이름에 있는 `'X'` 를 주목하십시오. `Py_DECREF()` 는 `NULL` 참조와 마주치면 충돌을 일으킵니다.) 이 예시를 수행하려면 소유하고 있는 참조를 보유하는데 사용하는 변수를 `NULL` 로 초기화하는 것이 중요합니다. 마찬가지로 반환 값은 `-1` (실패) 로 설정되고 마지만 호출이 성공한 뒤에야 성공으로 설정됩니다.

## 파이썬 임베딩하기

확장 작성자들과는 달리 파이썬 인터프리터를 임베딩 하는 사람들만이 걱정해야 하는 한가지 중요한 문제는 파이썬 인터프리터의 초기화, 그리고 아마도 마무리일 것입니다. 인터프리터의 대부분의 기능은 인터프리터가 초기화 된 이후에 사용할 수 있습니다.

기본적인 초기화 함수는 `Py_Initialize()` 입니다. 이 함수는 로드된 모듈 테이블을 초기화 하고 기본 모듈인 `builtins`, `__main__`, 그리고 `sys` 를 생성합니다. 또한 모듈 검색 경로 (`sys.path`) 를 초기화합니다

`Py_Initialize()` does not set the “script argument list” (`sys.argv`). If this variable is needed by Python code that will be executed later, setting `PyConfig.argv` and `PyConfig.parse_argv` must be set: see Python Initialization Configuration.

대부분의 시스템에서 (특별히 유닉스와 윈도우는 세부적인 부분이 조금 다르긴 하지만) `Py_Initialize()` 는 파이썬 인터프리터를 기준으로 고정된 위치에 파이썬 라이브러리가 있다고 가정하여 표준 파이썬 인터프리터 실행 파일에 대한 최선의 추측을 바탕으로 바탕으로 모듈 검색 경로를 계산합니다. 특히 셸 명령어 검색 경로 (환경 변수 `PATH`) 에서 `python` 이라는 이름의 실행 파일이 발견되는 부모 디렉터리를 기준으로 `lib/pythonX.Y` 같은 이름을 가진 디렉터리를 찾습니다.

예를 들어 파이썬 실행 파일이 `/usr/local/bin/python` 에서 발견된다면 라이브러리는 `/usr/local/lib/pythonX.Y` 에 있는 것으로 가정합니다. (실제로 이 특정 경로는 `PATH` 를 따라 `python` 이라는 이름의 실행 파일이 발견되지 않을 때 사용되는 “fallback” 경로이기도 합니다.) 유저는 환경 변수 `PYTHONHOME` 를 설정하여 이 동작을 재정의하거나 `PYTHONPATH` 를 설정하여 표준 경로 앞에 추가적인 디렉터리를 추가할 수 있습니다.

The embedding application can steer the search by setting `PyConfig.program_name` before calling `Py_InitializeFromConfig()`. Note that `PYTHONHOME` still overrides this and `PYTHONPATH` is still inserted in front of the standard path. An application that requires total control has to provide its own implementation of `Py_GetPath()`, `Py_GetPrefix()`, `Py_GetExecPrefix()`, and `Py_GetProgramFullPath()` (all defined in `Modules/getpath.c`).

가끔은 파이썬을 “uninitialize” 하는 것이 바람직합니다. 예를 들어 애플리케이션이 다시 시작하거나 (`Py_Initialize()` 다시 호출하기) 애플리케이션에서 파이썬의 사용이 끝나 파이썬이 할당한 메모리를 해제하려고 할 수 있습니다. `Py_FinalizeEx()` 를 호출하여 이를 달성할 수 있습니다. 함수 `Py_IsInitialized()` 는 파이썬이 현재 초기화된 상태에 있을 경우 참을 반환합니다. 이 함수들에 대한 자세한 내용은 다른 장에서 제공됩니다. `Py_FinalizeEx()` 가 파이썬 인터프리터가 할당한 모든 메모리를 해제하지는 않는다는 점에 유의해야 합니다. 예를 들어, 현재 확장 모듈에서 할당한 메모리는 해제할 수 없습니다.

## 디버깅 빌드

파이썬은 인터프리터와 확장 모듈들에 대한 추가적인 검사를 가능하게 하는 여러 매크로를 사용하여 빌드될 수 있습니다. 이러한 검사는 런타임에 많은 오버헤드를 추가하는 경향이 있으므로 기본적으로 실행되지 않습니다.

A full list of the various types of debugging builds is in the file `Misc/SpecialBuilds.txt` in the Python source distribution. Builds are available that support tracing of reference counts, debugging the memory allocator, or low-level profiling of the main interpreter loop. Only the most frequently used builds will be described in the remainder of this section.

Py_DEBUG

Compiling the interpreter with the `Py_DEBUG` macro defined produces what is generally meant by a debug build of Python. `Py_DEBUG` is enabled in the Unix build by adding `--with-pydebug` to the `./configure` command. It is also implied by the presence of the not-Python-specific `_DEBUG` macro. When `Py_DEBUG` is enabled in the Unix build, compiler optimization is disabled.

In addition to the reference count debugging described below, extra checks are performed, see Python Debug Build.

Defining `Py_TRACE_REFS` enables reference tracing (see the `configure --with-trace-refs option`). When defined, a circular doubly linked list of active objects is maintained by adding two extra fields to every `PyObject`. Total allocations are tracked as well. Upon exit, all existing references are printed. (In interactive mode this happens after every statement run by the interpreter.)

자세한 내용은 파이썬 소스 배포판 안의 `Misc/SpecialBuilds.txt` 를 참조하십시오.

## Recommended third party tools

The following third party tools offer both simpler and more sophisticated approaches to creating C, C++ and Rust extensions for Python:

- Cython

- cffi

- HPy

- nanobind (C++)

- Numba

- pybind11 (C++)

- PyO3 (Rust)

- SWIG

Using tools such as these can help avoid writing code that is tightly bound to a particular version of CPython, avoid reference counting errors, and focus more on your own code than on using the CPython API. In general, new versions of Python can be supported by updating the tool, and your code will often use newer and more efficient APIs automatically. Some tools also support compiling for other implementations of Python from a single set of sources.

These projects are not supported by the same people who maintain Python, and issues need to be raised with the projects directly. Remember to check that the project is still maintained and supported, as the list above may become outdated.

더 보기

Python Packaging User Guide: Binary Extensions

  The Python Packaging User Guide not only covers several available tools that simplify the creation of binary extensions, but also discusses the various reasons why creating an extension module may be desirable in the first place.