답변:
그것은의 동적 배열 . 실용적 증거 : 색인에 상관없이 색인 생성에는 시간이 많이 걸립니다 (물론 아주 작은 차이 (0.0013 µsec!)).
...>python -m timeit --setup="x = [None]*1000" "x[500]"
10000000 loops, best of 3: 0.0579 usec per loop
...>python -m timeit --setup="x = [None]*1000" "x[0]"
10000000 loops, best of 3: 0.0566 usec per loop
IronPython 또는 Jython에서 링크 된 목록을 사용하면 놀라 울 것입니다. 목록이 동적 배열이라는 가정하에 널리 사용되는 많은 라이브러리의 성능을 망칠 것입니다.
x=[None]*1000
가능한 목록 액세스 차이의 측정이 다소 부정확합니다. 초기화를 분리해야합니다.-s "x=[None]*100" "x[0]"
실제로 C 코드는 매우 간단합니다. 하나의 매크로를 확장하고 관련이없는 주석을 정리하면 기본 구조는에 listobject.h
있으며 목록을 다음과 같이 정의합니다.
typedef struct {
PyObject_HEAD
Py_ssize_t ob_size;
/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item;
/* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
* Invariants:
* 0 <= ob_size <= allocated
* len(list) == ob_size
* ob_item == NULL implies ob_size == allocated == 0
*/
Py_ssize_t allocated;
} PyListObject;
PyObject_HEAD
참조 횟수와 유형 식별자를 포함합니다. 따라서 전체적으로 할당되는 벡터 / 배열입니다. 이러한 배열이 가득 찼을 때 크기를 조정하는 코드는입니다 listobject.c
. 실제로 배열을 두 배로 늘리지는 않지만 할당하여 자랍니다.
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
new_allocated += newsize;
newsize
요청 된 크기는 매번 용량 에 따라 달라집니다 (필수 요소 수를 하나씩 지정하는 대신 임의의 수의 요소 allocated + 1
를 사용할 수 있기 때문은 아닙니다 ).extend
append
Python FAQ 도 참조하십시오 .
array
모듈 또는 NumPy가 선호됩니다.
이것은 구현에 따라 다르지만 IIRC :
ArrayList
따라서 그들은 모두 O (1) 랜덤 액세스를 갖습니다.
O(1)
목록 인덱싱은 매우 일반적이고 유효한 가정이기 때문에 구현을 감수하지 않습니다.
Laurent Luce의 기사 "Python list implementation"을 제안 합니다. 필자가 CPython에서 목록이 구현되는 방법을 설명 하고이 목적을 위해 훌륭한 다이어그램을 사용하기 때문에 정말 유용했습니다.
객체 C 구조 나열
CPython의 목록 오브젝트는 다음 C 구조로 표시됩니다.
ob_item
목록 요소에 대한 포인터 목록입니다. 할당은 메모리에 할당 된 슬롯 수입니다.typedef struct { PyObject_VAR_HEAD PyObject **ob_item; Py_ssize_t allocated; } PyListObject;
할당 된 슬롯과 목록 크기의 차이를 확인하는 것이 중요합니다. 목록의 크기는
len(l)
입니다. 할당 된 슬롯 수는 메모리에 할당 된 수입니다. 종종, 할당 된 크기가 크기보다 클 수 있음을 알 수 있습니다.realloc
새 요소가 목록에 추가 될 때마다 호출 할 필요 가 없습니다.
...
추가
리스트에 정수를 추가합니다 :
l.append(1)
. 무슨 일이야?
계속해서 요소를 하나 더 추가합니다 :
l.append(2)
.list_resize
n + 1 = 2로 호출되지만 할당 된 크기가 4이므로 더 많은 메모리를 할당 할 필요가 없습니다. 정수 2 개를 더 추가 할 때도 마찬가지입니다 :l.append(3)
,l.append(4)
. 다음 다이어그램은 우리가 지금까지 가지고있는 것을 보여줍니다.
...
끼워 넣다
...
팝
당신이 마지막 요소를 팝업 할 때 :
l.pop()
,listpop()
라고합니다.list_resize
내부에서 호출listpop()
되고 새 크기가 할당 된 크기의 절반보다 작 으면 목록이 축소됩니다.슬롯 4가 여전히 정수를 가리키는 것을 볼 수 있지만 중요한 것은 이제 4의 목록 크기입니다. 에
list_resize()
, 크기 - 1 = 4 - 1 = 3에서 6 개 슬롯 수축 및리스트의 새로운 크기가 현재 3 있도록 할당 된 슬롯의 절반 미만이다.
...
aggregation
아닙니다 composition
. 작곡 목록도 있었으면 좋겠다.
다른 사람들이 위에서 언급했듯이, 목록 (눈에 띄게 큰 경우)은 고정 된 양의 공간을 할당하고, 그 공간이 채워지면 더 많은 양의 공간을 할당하고 요소를 복사하여 구현됩니다.
일반성을 잃지 않고 메소드가 O (1)로 상각되는 이유를 이해하려면 = 2 ^ n 요소를 삽입했으며 이제 테이블을 2 ^ (n + 1) 크기로 두 배로 늘려야합니다. 이는 현재 2 ^ (n + 1) 작업을 수행하고 있음을 의미합니다. 마지막 사본에서는 2 ^ n 작업을 수행했습니다. 그 전에 우리는 2 ^ (n-1) ... 8,4,2,1까지 줄였습니다. 이제 합산하면 1 + 2 + 4 + 8 + ... + 2 ^ (n + 1) = 2 ^ (n + 2)-1 <4 * 2 ^ n = O (2 ^ n) = O (a) 총 삽입 (즉, O (1) 상각 시간). 또한 테이블이 삭제를 허용하는 경우 테이블 축소는 다른 요소 (예 : 3x)로 수행되어야합니다.
파이썬의 목록은 배열과 유사하며 여러 값을 저장할 수 있습니다. 목록은 변경할 수 있으므로 변경할 수 있습니다. 더 중요한 것은리스트를 만들 때 파이썬은 자동으로 해당리스트 변수에 대한 reference_id를 만듭니다. 다른 변수를 지정하여 변경하면 기본 목록이 변경됩니다. 예를 들어 봅시다 :
list_one = [1,2,3,4]
my_list = list_one
#my_list: [1,2,3,4]
my_list.append("new")
#my_list: [1,2,3,4,'new']
#list_one: [1,2,3,4,'new']
추가 my_list
하지만 기본 목록이 변경되었습니다. 그 의미의 목록은 참조로 사본 목록으로 지정되지 않았습니다.