Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python List オブジェクトを深掘りしてみた

Avatar for Tomoya Hiroe Tomoya Hiroe
September 20, 2026

Python List オブジェクトを深掘りしてみた

横浜国立大学Lumos と法政大学 CodeMates との合同LT会で発表したものです。普段なんとなく使用している Listオブジェクトについて少しだけ勉強をしました。スライドに出てきたコードは GitHub Gistにあげています。marimo を使用したものなので、 `uv run marimo edit pylist.py` などしていただければ、ノートブック形式で実行できます。

Avatar for Tomoya Hiroe

Tomoya Hiroe

September 20, 2026

Other Decks in Programming

Transcript

  1. Python list What's Really Inside a Python list CodeMates &

    Lumos LT tomoyahiroe from Lumos @ 2026.09.19
  2. 01 tomoyahiroe M2 / PyCon JP 2026 Terraform / Google

    Cloud marimo / / Sitcom / TBBT, Friends / Rebuild.fm
  3. 01 list PYTHON OUTPUT a = [10, "x", None] a:

    [10, 'x', None] print("a:", a) a[0]: 10 print("a[0]: ", a[0]) a.insert(0, 5): [5, 10, 'x', None] a.insert(0, 5) print("a.insert(0, 5): ", a)
  4. 01 list CPython listobject.h object.h typedef struct { PyObject_VAR_HEAD PyObject_VAR_HEAD

    PyVarObject ob_base; PyObject **ob_item; Py_ssize_t allocated; } PyListObject; ob_item … allocated … typedef struct { PyObject ob_base; Py_ssize_t ob_size; } PyVarObject; ob_size … ob_base … ob_refcnt ob_type cpython/Include/cpython/listobject.h (3.14) / Include/object.h (3.14) / docs.python.org — List Objects (3.14)
  5. 01 list Flat 40 size_t Py_ssize_t 64bit CPython 3.14 /

    64bit / struct sys.getsizeof([]) 40 56 8
  6. 01 list list 56 PYTHON struct import sys typedef struct

    { 40 16 uintptr_t _gc_next; sys.getsizeof([]) OUTPUT uintptr_t _gc_prev; } PyGC_Head; GC 56 2 int str list dict
  7. 02 list list PYTHON OUTPUT 8 a = [10, 20,

    30] 0100000000000000 address = id(a) f0d8ea0601000000 0300000000000000 raw = bytes( (ctypes.c_char * d056410e01000000 40) .from_address(address) ) print(raw.hex(" ", 8)) 0400000000000000 40 8 5
  8. 02 list 8 PYTHON 0 7 1 ob_refcnt for i

    in range(5): 8 15 4411021552 ob_type 16 23 3 ob_size 24 31 4534130384 ob_item 32 39 4 allocated val = struct.unpack_from( "<Q", raw, i * 8 )[ 0] print(i * 8, val) "<Q" … 3 64bit 4
  9. 02 list PYTHON class PyListObject(ctypes.Structure): _fields_ = [ ( "ob_refcnt",

    ctypes.c_ssize_t), ( "ob_type", ctypes.c_void_p), ( "ob_size", ctypes.c_ssize_t), ( "ob_item", ctypes.POINTER(ctypes.c_void_p)), ( "allocated", ctypes.c_ssize_t), ] lo = PyListObject.from_address(id(a)) lo.ob_size
  10. 02 list ob_refcnt ob_size ob_refcnt PYTHON / OUTPUT sys.getrefcount(a) #2

    lo.ob_refcnt #1 sys.getrefcount(None) # 3221225472 getrefcount 1 +1 ob_size len(a) #3 lo.ob_size #3 None len() immortal object PEP 683 O(1)
  11. 02 list ob_size allocated ob_size 3 allocated 4 +40 ob_size

    4 allocated 4 +50 ob_size 5 allocated 8 +60 ob_size 6 allocated 8 +70 ob_size 7 allocated 8 PYTHON a.append(40) print(lo.ob_size, lo.allocated) a.append(50) print(lo.ob_size, lo.allocated) append O(1) amortized
  12. 03 1 1 — 2 — ctypes addr = ctypes.cast(lo.ob_item,

    lo.ob_item[0] ctypes.c_void_p).value # 4411336440 # 4578435888 lo.ob_item[0] == id(a[0]) raw = bytes((ctypes.c_char * 8) # True .from_address(addr)) struct.unpack("<Q", raw)[0] lo.ob_item[0] is id(a[0]) # 4411336440 # False id(a[0]) = 4411336440 int
  13. 03 8 n PYTHON n = lo.ob_size raw = bytes((ctypes.c_char

    * (8 * n)) .from_address(addr)) ptrs = [] for i in range(n): ptrs.append( struct.unpack_from( "<Q", raw, i*8)[0] ) print(ptrs[i], id(a[i]), ptrs[i] == id(a[i])) 8 [0] 4411336440 [1] 4411336760 [2] 4411337080 [3] 4411337400 [4] 4411337720
  14. 04 PYTHON OUTPUT for i in range(n): 10 <class 'int'>

    obj = ctypes.cast( 20 <class 'int'> ptrs[i], ctypes.py_object 30 <class 'int'> ).value 40 <class 'int'> print(obj, type(obj)) 50 <class 'int'> py_object .value Python int
  15. 04 PYTHON OUTPUT 24 …0a000000 10 …14000000 20 …1e000000 30

    …28000000 40 …32000000 50 r = bytes((ctypes.c_char * 32) .from_address(ptrs[i])) digit = struct.unpack_from( "<I", r, 24 )[0] 0 15 … ob_refcnt / ob_type 16 23 … lv_tag 24 27 … ob_digit[0] 1 4 / 30bit 0a 10 32 50 / CPython 3.12+