# 공통 객체 구조체

파이썬의 객체 형 정의에 사용되는 많은 구조체가 있습니다. 이 섹션에서는 이러한 구조체와 사용 방법에 관해 설명합니다.

## 기본 객체 형과 매크로

모든 파이썬 객체는 궁극적으로 객체의 메모리 표현의 처음에서 적은 수의 필드를 공유합니다. 이들은 `PyObject`와 `PyVarObject` 형으로 표시되며, 다른 모든 파이썬 객체의 정의에서, 직접 또는 간접적으로, 사용되는 일부 매크로의 확장을 통해 정의됩니다.

`PyObject`

  모든 객체 형은 이 형의 확장입니다. 이것은 파이썬이 객체에 대한 포인터를 객체로 취급하는 데 필요한 정보를 포함하는 형입니다. 일반적인 “릴리스” 빌드에는, 객체의 참조 횟수와 해당 형 객체에 대한 포인터만 포함됩니다. 실제로 `PyObject`로 선언된 것은 없지만, 파이썬 객체에 대한 모든 포인터를 `PyObject*`로 캐스트 할 수 있습니다. `Py_REFCNT`와 `Py_TYPE` 매크로를 사용하여 멤버에 액세스해야 합니다.

`PyVarObject`

  이것은 `ob_size` 필드를 추가하는 `PyObject`의 확장입니다. 이것은 길이라는 개념을 가진 객체에만 사용됩니다. 이 형은 종종 파이썬/C API에 나타나지 않습니다. `Py_REFCNT`, `Py_TYPE` 및 `Py_SIZE` 매크로를 사용하여 멤버에 액세스해야 합니다.

`PyObject_HEAD`

  길이가 변하지 않는 객체를 나타내는 새로운 형을 선언할 때 사용되는 매크로입니다. PyObject_HEAD 매크로는 다음과 같이 확장됩니다:

      PyObject ob_base;

  위의 `PyObject` 설명서를 참조하십시오.

`PyObject_VAR_HEAD`

  인스턴스마다 길이가 다른 객체를 나타내는 새로운 형을 선언할 때 사용되는 매크로입니다. PyObject_VAR_HEAD 매크로는 다음과 같이 확장됩니다:

      PyVarObject ob_base;

  위의 `PyVarObject` 설명서를 참조하십시오.

`Py_TYPE`(o)

  이 매크로는 파이썬 객체의 `ob_type` 멤버에 액세스하는 데 사용됩니다. 다음으로 확장됩니다:

      (((PyObject*)(o))->ob_type)

int `Py_IS_TYPE`(PyObject *o, PyTypeObject *type)

  객체 o의 형이 type이면 0이 아닌 값을 반환합니다. 그렇지 않으면 0을 반환합니다. `Py_TYPE(o) == type`과 동등합니다.

  버전 3.9에 추가.

void `Py_SET_TYPE`(PyObject *o, PyTypeObject *type)

  객체 o의 형을 type으로 설정합니다.

  버전 3.9에 추가.

`Py_REFCNT`(o)

  이 매크로는 파이썬 객체의 `ob_refcnt` 멤버에 액세스하는 데 사용됩니다. 다음으로 확장됩니다:

      (((PyObject*)(o))->ob_refcnt)

void `Py_SET_REFCNT`(PyObject *o, Py_ssize_t refcnt)

  객체 o의 참조 횟수를 refcnt로 설정합니다.

  버전 3.9에 추가.

`Py_SIZE`(o)

  이 매크로는 파이썬 객체의 `ob_size` 멤버에 액세스하는 데 사용됩니다. 다음으로 확장됩니다:

      (((PyVarObject*)(o))->ob_size)

void `Py_SET_SIZE`(PyVarObject *o, Py_ssize_t size)

  객체 o의 크기를 size로 설정합니다.

  버전 3.9에 추가.

`PyObject_HEAD_INIT`(type)

  이것은 새로운 `PyObject` 형의 초기화 값으로 확장되는 매크로입니다. 이 매크로는 다음으로 확장됩니다:

      _PyObject_EXTRA_INIT
      1, type,

`PyVarObject_HEAD_INIT`(type, size)

  이것은 `ob_size` 필드를 포함하여, 새로운 `PyVarObject` 형의 초기화 값으로 확장되는 매크로입니다. 이 매크로는 다음으로 확장됩니다:

      _PyObject_EXTRA_INIT
      1, type, size,

## 함수와 메서드 구현

`PyCFunction`

  대부분 파이썬 콜러블을 C로 구현하는 데 사용되는 함수 형. 이 형의 함수는 두 개의 `PyObject*` 매개 변수를 취하고 하나의 값을 반환합니다. 반환 값이 NULL이면, 예외가 설정되어 있어야 합니다. `NULL`이 아니면, 반환 값은 파이썬에 노출된 함수의 반환 값으로 해석됩니다. 함수는 새로운 참조를 반환해야 합니다.

  함수 서명은 다음과 같습니다:

      PyObject *PyCFunction(PyObject *self,
                            PyObject *args);

`PyCFunctionWithKeywords`

  서명이 `METH_VARARGS | METH_KEYWORDS` 인 파이썬 콜러블을 C로 구현하는 데 사용되는 함수 형. 함수 서명은 다음과 같습니다:

      PyObject *PyCFunctionWithKeywords(PyObject *self,
                                        PyObject *args,
                                        PyObject *kwargs);

`_PyCFunctionFast`

  서명이 `METH_FASTCALL` 인 파이썬 콜러블을 C로 구현하는 데 사용되는 함수 형. 함수 서명은 다음과 같습니다:

      PyObject *_PyCFunctionFast(PyObject *self,
                                 PyObject *const *args,
                                 Py_ssize_t nargs);

`_PyCFunctionFastWithKeywords`

  서명이 `METH_FASTCALL | METH_KEYWORDS` 인 파이썬 콜러블을 C로 구현하는 데 사용되는 함수 형. 함수 서명은 다음과 같습니다:

      PyObject *_PyCFunctionFastWithKeywords(PyObject *self,
                                             PyObject *const *args,
                                             Py_ssize_t nargs,
                                             PyObject *kwnames);

`PyCMethod`

  서명이 `METH_METHOD | METH_FASTCALL | METH_KEYWORDS` 인 파이썬 콜러블을 C로 구현하는 데 사용되는 함수 형. 함수 서명은 다음과 같습니다:

      PyObject *PyCMethod(PyObject *self,
                          PyTypeObject *defining_class,
                          PyObject *const *args,
                          Py_ssize_t nargs,
                          PyObject *kwnames)

  버전 3.9에 추가.

`PyMethodDef`

  확장형의 메서드를 기술하는 데 사용되는 구조체. 이 구조체에는 네 개의 필드가 있습니다:

  필드 | C 형 | 의미
  --- | --- | ---
  `ml_name` | const char * | 메서드의 이름
  `ml_meth` | PyCFunction | C 구현에 대한 포인터
  `ml_flags` | int | 호출 구성 방법을 나타내는 플래그 비트
  `ml_doc` | const char * | 독스트링의 내용을 가리킵니다

`ml_meth`는 C 함수 포인터입니다. 함수는 형이 다를 수 있지만, 항상 `PyObject*`를 반환합니다. 함수가 `PyCFunction`이 아니면, 컴파일러는 메서드 테이블에서 캐스트를 요구합니다. `PyCFunction`이 첫 번째 매개 변수를 `PyObject*`로 정의하더라도, 일반적으로 메서드 구현은 self 객체의 특정 C 형을 사용합니다.

`ml_flags` 필드는 다음 플래그를 포함 할 수 있는 비트 필드입니다. 개별 플래그는 호출 규칙이나 바인딩 규칙을 나타냅니다.

다음과 같은 호출 규칙이 있습니다:

`METH_VARARGS`

  이는 메서드가 `PyCFunction` 형인 일반적인 호출 규칙입니다. 함수는 두 개의 `PyObject*` 값을 기대합니다. 첫 번째는 메서드의 self 객체입니다; 모듈 함수의 경우, 모듈 객체입니다. 두 번째 매개 변수(종종 args라고 합니다)는 모든 인자를 나타내는 튜플 객체입니다. 이 매개 변수는 일반적으로 `PyArg_ParseTuple()`이나 `PyArg_UnpackTuple()`을 사용하여 처리됩니다.

`METH_VARARGS | METH_KEYWORDS`

  이러한 플래그가 있는 메서드는 `PyCFunctionWithKeywords` 형이어야 합니다. 이 함수는 세 개의 매개 변수를 기대합니다: self, args, kwargs. 여기서 kwargs는 모든 키워드 인자의 딕셔너리이거나 키워드 인자가 없으면 `NULL`일 수 있습니다. 매개 변수는 일반적으로 `PyArg_ParseTupleAndKeywords()`를 사용하여 처리됩니다.

`METH_FASTCALL`

  위치 인자만 지원하는 빠른 호출 규칙. 메서드의 형은 `_PyCFunctionFast` 입니다. 첫 번째 매개 변수는 self이고, 두 번째 매개 변수는 인자를 나타내는 `PyObject*` 값의 C 배열이며, 세 번째 매개 변수는 인자 수(배열의 길이)입니다.

  이것은 제한된 API의 일부가 아닙니다.

  버전 3.7에 추가.

`METH_FASTCALL | METH_KEYWORDS`

  `_PyCFunctionFastWithKeywords` 형의 메서드를 사용하여, 키워드 인자도 지원하는 `METH_FASTCALL`의 확장. 키워드 인자는 벡터콜(vectorcall) 프로토콜과 같은 방식으로 전달됩니다: 추가의 네 번째 `PyObject*` 매개 변수가 있는데, 키워드 인자의 이름(문자열임이 보장됩니다)을 나타내는 튜플이거나 키워드가 없으면 `NULL`일 수 있습니다. 키워드 인자의 값은 위치 인자 다음에 args 배열에 저장됩니다.

  이것은 제한된 API의 일부가 아닙니다.

  버전 3.7에 추가.

`METH_METHOD | METH_FASTCALL | METH_KEYWORDS`

  정의하는 클래스(defining class), 즉, 문제의 메서드를 포함하는 클래스를 지원하는 `METH_FASTCALL | METH_KEYWORDS`의 확장. 정의하는 클래스는 `Py_TYPE(self)`의 슈퍼 클래스일 수 있습니다.

  메서드는 `PyCMethod` 형이어야 하는데, `self` 뒤에 `defining_class` 인자가 추가된 `METH_FASTCALL | METH_KEYWORDS`와 같습니다.

  버전 3.9에 추가.

`METH_NOARGS`

  매개 변수가 없는 메서드는 `METH_NOARGS` 플래그로 나열되어 있으면, 인자가 주어졌는지 확인할 필요가 없습니다. `PyCFunction` 형이어야 합니다. 첫 번째 매개 변수의 이름은 일반적으로 self이며 모듈이나 객체 인스턴스에 대한 참조를 보유합니다. 모든 경우에 두 번째 매개 변수는 `NULL`입니다.

`METH_O`

  `"O"` 인자로 `PyArg_ParseTuple()`을 호출하는 대신, 단일 객체 인자가 있는 메서드는 `METH_O` 플래그로 나열 할 수 있습니다. `PyCFunction` 형이고, self 매개 변수와 단일 인자를 나타내는 `PyObject*` 매개 변수를 갖습니다.

이 두 상수는 호출 규칙을 나타내는 데 사용되지 않고 클래스의 메서드와 함께 사용할 때 바인딩을 나타냅니다. 모듈에 정의된 함수에는 사용할 수 없습니다. 이러한 플래그 중 최대 하나를 주어진 메서드에 대해 설정할 수 있습니다.

`METH_CLASS`

  메서드로 형의 인스턴스가 아닌 형 객체가 첫 번째 매개 변수로 전달됩니다. `classmethod()` 내장 함수를 사용할 때 만들어지는 것과 유사한 클래스 메서드(class methods)를 만드는 데 사용됩니다.

`METH_STATIC`

  메서드로 형의 인스턴스가 아닌 `NULL`이 첫 번째 매개 변수로 전달됩니다. `staticmethod()` 내장 함수를 사용할 때 만들어지는 것과 유사한 정적 메서드(static methods)를 만드는 데 사용됩니다.

하나의 다른 상수는 같은 메서드 이름을 가진 다른 정의 대신 메서드가 로드되는지를 제어합니다.

`METH_COEXIST`

  기존 정의 대신 메서드가 로드됩니다. METH_COEXIST가 없으면, 기본값은 반복되는 정의를 건너뛰는 것입니다. 슬롯 래퍼가 메서드 테이블 전에 로드되므로, 예를 들어 sq_contains 슬롯의 존재는 `__contains__()`라는 래핑 된 메서드를 생성하고 같은 이름의 해당 PyCFunction을 로드하지 않습니다. 플래그가 정의되면, PyCFunction이 래퍼 객체 자리에 로드되고 슬롯과 공존합니다. 이는 PyCFunction에 대한 호출이 래퍼 객체 호출보다 최적화되어 있기 때문에 유용합니다.

## 확장형의 어트리뷰트 액세스

`PyMemberDef`

  C 구조체 멤버에 해당하는 형의 어트리뷰트를 기술하는 구조체. 필드는 다음과 같습니다:

  필드 | C 형 | 의미
  --- | --- | ---
  `name` | const char * | 멤버의 이름
  `type` | int | C 구조체에 있는 멤버의 형
  `offset` | Py_ssize_t | 멤버가 형의 객체 구조체에 위치하는 바이트 단위의 오프셋
  `flags` | int | 필드가 읽기 전용인지 쓰기 가능한지를 나타내는 플래그 비트
  `doc` | const char * | 독스트링의 내용을 가리킵니다

  `type`은 다양한 C 형에 해당하는 많은 `T_` 매크로 중 하나일 수 있습니다. 멤버가 파이썬에서 액세스 될 때, 동등한 파이썬 형으로 변환됩니다.

  매크로 이름 | C 형
  --- | ---
  T_SHORT | short
  T_INT | int
  T_LONG | long
  T_FLOAT | float
  T_DOUBLE | double
  T_STRING | const char *
  T_OBJECT | PyObject *
  T_OBJECT_EX | PyObject *
  T_CHAR | char
  T_BYTE | char
  T_UBYTE | unsigned char
  T_UINT | unsigned int
  T_USHORT | unsigned short
  T_ULONG | unsigned long
  T_BOOL | char
  T_LONGLONG | long long
  T_ULONGLONG | unsigned long long
  T_PYSSIZET | Py_ssize_t

  멤버가 `NULL`일 때 `T_OBJECT`는 `None`을 반환하고 `T_OBJECT_EX`는 `AttributeError`를 발생시킨다는 점에서 `T_OBJECT`와 `T_OBJECT_EX`가 다릅니다. `T_OBJECT_EX`가 `T_OBJECT`보다 해당 어트리뷰트에 대한 `del` 문 사용을 더 올바르게 처리하므로, `T_OBJECT`보다 `T_OBJECT_EX`를 사용하십시오.

  `flags`는 쓰기와 읽기 액세스를 위해 `0`이거나, 읽기 전용 액세스를 위해 `READONLY` 일 수 있습니다. `type`에 `T_STRING`을 사용한다는 것은 `READONLY`를 뜻합니다. `T_STRING` 데이터는 UTF-8로 해석됩니다. `T_OBJECT`와 `T_OBJECT_EX` 멤버만 삭제될 수 있습니다. (`NULL`로 설정됩니다).

  힙 할당형 (`PyType_FromSpec()`이나 유사한 것을 사용하여 만들어진), `PyMemberDef`는 형 객체의 `tp_dictoffset`, `tp_weaklistoffset` 및 `tp_vectorcall_offset`에 해당하는 특수 멤버 `__dictoffset__`, `__weaklistoffset__` 및 `__vectorcalloffset__`에 대한 정의를 포함할 수 있습니다. `T_PYSSIZET`과 `READONLY`로 정의해야 합니다, 예를 들면:

      static PyMemberDef spam_type_members[] = {
          {"__dictoffset__", T_PYSSIZET, offsetof(Spam_object, dict), READONLY},
          {NULL}  /* Sentinel */
      };

PyObject* `PyMember_GetOne`(const char *obj_addr, struct PyMemberDef *m)

  Get an attribute belonging to the object at address obj_addr. The attribute is described by `PyMemberDef` m. Returns `NULL` on error.

int `PyMember_SetOne`(char *obj_addr, struct PyMemberDef *m, PyObject *o)

  Set an attribute belonging to the object at address obj_addr to object o. The attribute to set is described by `PyMemberDef` m. Returns `0` if successful and a negative value on failure.

`PyGetSetDef`

  형에 대한 프로퍼티 같은 액세스를 정의하는 구조체. `PyTypeObject.tp_getset` 슬롯에 대한 설명도 참조하십시오.

  필드 | C 형 | 의미
  --- | --- | ---
  name | const char * | 어트리뷰트 이름
  get | getter | C function to get the attribute
  set | setter | 어트리뷰트를 설정하거나 삭제하는 선택적 C 함수, 생략되면 어트리뷰트는 읽기 전용입니다
  doc | const char * | 선택적 독스트링
  closure | void * | getter와 setter에 추가 데이터를 제공하는 선택적 함수 포인터

  `get` 함수는 하나의 `PyObject*` 매개 변수(인스턴스)와 함수 포인터(연관된 `closure`)를 받아들입니다:

      typedef PyObject *(*getter)(PyObject *, void *);

  성공하면 새 참조를 반환하고, 실패하면 설정된 예외와 함께 `NULL`을 반환해야 합니다.

  `set` 함수는 두 개의 `PyObject*` 매개 변수(인스턴스와 설정할 값)와 함수 포인터(연관된 `closure`)를 받아들입니다:

      typedef int (*setter)(PyObject *, PyObject *, void *);

  어트리뷰트를 삭제해야 하는 경우 두 번째 매개 변수는 `NULL`입니다. 성공하면 `0`을, 실패하면 설정된 예외와 함께 `-1`을 반환해야 합니다.