본문 바로가기
C

PyList_New(size 또는 0)

by yororing 2024. 8. 30.

00 개요

  • 파이썬 리스트를 생성하는 PyList_New() 함수에 대한 정리
  • 코드 분석 중 PyList_New() 함수는, 인자로 생성될 list의 크기를 줘야만 하는 함수인 줄 알았는데 PyObject *result = PyList_New(0)으로 선언한 뒤 result에 값이 추가가 되는 것을 보고 멘붕와서 이에 대한 설명을 하고자 함
  • 요약: PyObject* myList = PyList_New(0); 실행 시
    • myList는 초기 크기가 0인 빈 Python 리스트로 생성됨
    • 이 리스트는 처음에는 요소를 포함하지 않지만, 이후에 요소 추가될 수 있음
    • Python의 리스트는 동적으로 크기 조정이 가능하기에, 처음에 크기가 0이어도 나중에 항목 추가 가능'

01 PyList_New(size) 함수

1. 정의

  • Python C API에서 제공되는 함수로, Python 리스트 객체 생성 시 사용됨

2. 문법

PyObject* PyList_New(Py_ssize_t size);
  • 입력 인자: size
    • 리스트의 초기 크기
    • Py_ssize_t는 signed size 타입으로, 리스트의 길이를 지정
    • 즉, 리스트에 포함될 요소의 수를 나타냄 
  • 반환 값: PyObject*
    • 생성된 Python 리스트 객체를 가리키는 포인터
    • 만약 메모리 할당에 실패하면 NULL을 반환

3. 동작 원리

1) 초기화:

  • PyList_New(size)는 주어진 size 크기를 가지는 새로운 리스트를 생성
  • 생성된 리스트는 초기화되어 있으며, 리스트의 각 요소는 NULL로 초기화 됨

2) 리스트 요소 초기화

  • 생성된 리스트의 크기는 size로 지정되지만, 리스트의 모든 요소는 아직 값이 할당되지 않아있는 상태
  • 각 요소는 NULL 포인터를 가짐
  • 즉, 리스트의 요소를 사용하기 전에 각각의 위치에 값을 할당해주어야 함

3) 메모리 관리

  • 리스트가 생성되면, Python의 메모리 관리 시스템에 의해 관리됨
  • 이는 garbage collection에 의해 처리됨
  • 리스트가 더 이상 사용되지 않으면 메모리가 자동으로 해제됨

4. 예시

PyObject* myList = PyList_New(3);  // 크기가 3인 리스트 생성

if (!myList) {                     // 메모리 할당 실패 시 처리
    return NULL;
}

// 각 리스트 요소에 값을 할당
PyList_SetItem(myList, 0, PyLong_FromLong(10));  // 첫 번째 요소에 10 추가
PyList_SetItem(myList, 1, PyLong_FromLong(20));  // 두 번째 요소에 20 추가
PyList_SetItem(myList, 2, PyLong_FromLong(30));  // 세 번째 요소에 30 추가
  • 설명:
    • 리스트 생성:
      • PyList_New(3)은 크기가 3인 리스트를 생성
      • 이 리스트는 [NULL, NULL, NULL]로 초기화됨
    • 요소 추가:
      • PyList_SetItem을 사용하여 리스트의 각 요소에 값을 할당
      • 이제 리스트는 [10, 20, 30]의 값을 가짐 
  • 중요한 주의사항 
    • 초기화 후 요소 설정: 
      • 리스트가 생성된 후, PyList_SetItem 또는 PyList_Append 등을 사용하여 리스트의 각 요소를 설정 필수
      • 초기화되지 않은 NULL 포인터가 남아 있으면, 잘못된 메모리 접근이나 프로그램 충돌이 발생 가능
    • 참조 카운트:
      • PyList_SetItem은 해당 위치의 기존 항목을 제거하고 새 항목을 삽입함
      • 이 과정에서 새로 삽입된 객체의 참조 카운트를 증가시키지 않음
      • 이는 성능 최적화를 위해서이며, 이로 인해 참조 카운트 관리에 주의 필요 - 추후에 더 알아보기

5. 요약

  • PyList_New(size)는 size 크기의 리스트를 생성하지만, 초기화된 상태에서는 리스트의 요소가 NULL로 설정됨
  • 이 함수로 생성된 리스트에 값을 추가하려면, PyList_SetItem 등을 사용해야 하며, 이를 통해 요소를 적절하게 설정 가능
  • Python의 리스트는 동적 배열로, 초기 크기를 설정한 후에도 동적으로 크기를 조정 가능하기에 처음에 크기가 0인 PyList_New(0)으로 리스트를 만들어도 나중에 이 리스트에 값을 추가할 수 있는 것!

02 Python 리스트의 동적 크기 조정

  • Python의 리스트는 동적 배열(dynamic array)
  • 리스트의 크기는 초기화 시에 정해지더라도, PyList_Append와 같은 함수를 사용해 리스트에 항목을 추가 가능
  • 이 과정에서 리스트의 내부 배열이 자동으로 확장

1. 예시

PyObject* myList = PyList_New(0);  // 빈 리스트 생성 (크기 0)
PyObject* item = PyLong_FromLong(42);
PyList_Append(myList, item);  // 리스트에 42 추가 (크기 1로 증가)
  • 초기화:
    • PyList_New(0)은 크기가 0인 빈 리스트 생성
    • 리스트에는 아직 요소가 없지만, 추가할 준비는 되어 있는 상태
  • 동적 확장:
    • PyList_Append(myList, item) 호출 시 Python 내부에서 리스트의 크기를 동적으로 조정하여 새로운 항목을 추가
  • 예시 설명:
    • 처음: myList는 빈 리스트
    • PyList_Append 호출 후: 리스트에 42가 추가되고, 리스트의 크기는 1이 됨 

2. PyList_New(size)의 의미 

  • PyList_New(0): 빈 리스트 생성. 리스트의 초기 크기는 0
  • 이후 PyList_Append 등을 통해 항목을 추가하면 크기가 자동으로 늘어남 
  • PyList_New(size): 주어진 size만큼의 크기를 가지는 리스트 생성. 리스트는 size만큼의 공간을 예약하지만, 해당 공간은 NULL 포인터로 초기화됨
  • 리스트의 각 요소에 값이 할당되지 않으면, NULL 포인터로 남아 있음 

3. 요약

  • PyList_New(0)은 크기가 0인 리스트를 생성하지만, Python의 리스트는 동적으로 크기를 조정할 수 있으므로 이후에 값이 추가될 수 있음
  • PyList_Append는 리스트에 값을 추가할 때, 리스트가 필요에 따라 크기를 자동으로 늘림
  • 따라서, 리스트의 초기 크기와 관계없이 항목을 자유롭게 추가 가능!