2011-03-03 4 views
2

나는 목록이있는 경우 :파이썬은 어떻게 작동합니까?

a.extend(range(5,10))

내가 이렇게 파이썬 않는 방법

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

을 얻을 확장 한 후

a = [1,2,3,4]

등을 사용하여 4 개 요소를 추가? 새로운 목록을 만들고 요소를 복사합니까 아니면 더 큰가? 그냥 확장을 사용하면 메모리를 중얼 거릴 것이라고 우려했습니다. 나는 10000 × 100으로 연장 1000000

+7

구현에 따라 다릅니다. –

+0

정보 주셔서 감사. – Martlark

답변

2

L.extend (M)는 상각 O (N) 여기서, N = LEN (m)가 너무 과도한 복사가 문제가되지 일반적이다. 시간이 일 수 있습니다.은 문제가됩니다. 확장 할 공간이 충분하지 않아 복사가 수행됩니다. 이것은 목록이 크고 개별 연장 통화에 대해 허용되는 시간의 한계가있는 경우 문제입니다.

문제에 대한보다 효율적인 데이터 구조를 찾아야하는 시점입니다. 나는 그것이 실제로 거의 문제가되지 않는다는 것을 안다.

여기 CPython과의 관련 코드는, 당신은 목록이

static PyObject * 
listextend(PyListObject *self, PyObject *b) 
{ 
    PyObject *it;  /* iter(v) */ 
    Py_ssize_t m;     /* size of self */ 
    Py_ssize_t n;     /* guess for size of b */ 
    Py_ssize_t mn;     /* m + n */ 
    Py_ssize_t i; 
    PyObject *(*iternext)(PyObject *); 

    /* Special cases: 
     1) lists and tuples which can use PySequence_Fast ops 
     2) extending self to self requires making a copy first 
    */ 
    if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) { 
     PyObject **src, **dest; 
     b = PySequence_Fast(b, "argument must be iterable"); 
     if (!b) 
      return NULL; 
     n = PySequence_Fast_GET_SIZE(b); 
     if (n == 0) { 
      /* short circuit when b is empty */ 
      Py_DECREF(b); 
      Py_RETURN_NONE; 
     } 
     m = Py_SIZE(self); 
     if (list_resize(self, m + n) == -1) { 
      Py_DECREF(b); 
      return NULL; 
     } 
     /* note that we may still have self == b here for the 
     * situation a.extend(a), but the following code works 
     * in that case too. Just make sure to resize self 
     * before calling PySequence_Fast_ITEMS. 
     */ 
     /* populate the end of self with b's items */ 
     src = PySequence_Fast_ITEMS(b); 
     dest = self->ob_item + m; 
     for (i = 0; i < n; i++) { 
      PyObject *o = src[i]; 
      Py_INCREF(o); 
      dest[i] = o; 
     } 
     Py_DECREF(b); 
     Py_RETURN_NONE; 
    } 

    it = PyObject_GetIter(b); 
    if (it == NULL) 
     return NULL; 
    iternext = *it->ob_type->tp_iternext; 

    /* Guess a result list size. */ 
    n = _PyObject_LengthHint(b, 8); 
    if (n == -1) { 
     Py_DECREF(it); 
     return NULL; 
    } 
    m = Py_SIZE(self); 
    mn = m + n; 
    if (mn >= m) { 
     /* Make room. */ 
     if (list_resize(self, mn) == -1) 
      goto error; 
     /* Make the list sane again. */ 
     Py_SIZE(self) = m; 
    } 
    /* Else m + n overflowed; on the chance that n lied, and there really 
    * is enough room, ignore it. If n was telling the truth, we'll 
    * eventually run out of memory during the loop. 
    */ 

    /* Run iterator to exhaustion. */ 
    for (;;) { 
     PyObject *item = iternext(it); 
     if (item == NULL) { 
      if (PyErr_Occurred()) { 
       if (PyErr_ExceptionMatches(PyExc_StopIteration)) 
        PyErr_Clear(); 
       else 
        goto error; 
      } 
      break; 
     } 
     if (Py_SIZE(self) < self->allocated) { 
      /* steals ref */ 
      PyList_SET_ITEM(self, Py_SIZE(self), item); 
      ++Py_SIZE(self); 
     } 
     else { 
      int status = app1(self, item); 
      Py_DECREF(item); /* append creates a new ref */ 
      if (status < 0) 
       goto error; 
     } 
    } 

    /* Cut back result list if initial guess was too large. */ 
    if (Py_SIZE(self) < self->allocated) 
     list_resize(self, Py_SIZE(self)); /* shrinking can't fail */ 

    Py_DECREF(it); 
    Py_RETURN_NONE; 

    error: 
    Py_DECREF(it); 
    return NULL; 
} 

PyObject * 
_PyList_Extend(PyListObject *self, PyObject *b) 
{ 
    return listextend(self, b); 
} 
3

파이썬의 documentation on it의 한 블록에하는 것보다 더 빠른 것을 수정하고있어 일부 코드의 주석이 있으므로 I'am도 물어 말한다 :

가 확장 지정된 목록에있는 모든 항목을 추가하여 목록에 추가하십시오. a[len(a):] = L에 해당합니다.

"어떻게"장면 뒤에서, 실제로 그것에 대해 걱정할 필요가 없습니다. 그것은이 목록을 변이합니다이

def extend(lst, iterable): 
    for x in iterable: 
     lst.append(x) 

같이 정의 된 것처럼

2

의미가 있습니다, 그것의 복사본을 생성하지 않습니다.

기본 구현에 따라 appendextend이 목록을 트리거하여 자체 데이터 구조를 복사 할 수 있지만 이는 정상적인 것이며 걱정할 필요가 없습니다. 예를 들어, 배열 기반 구현은 일반적으로 기저 배열을 기하 급수적으로 증가시키고 그렇게 할 때 요소 목록을 복사해야합니다.

0

파이썬은 어떻게합니까? 새로운 목록을 만들고 요소를 복사합니까 아니면 더 큰가?

>>> a = ['apples', 'bananas'] 
>>> b = a 
>>> a is b 
True 
>>> c = ['apples', 'bananas'] 
>>> a is c 
False 
>>> a.extend(b) 
>>> a 
['apples', 'bananas', 'apples', 'bananas'] 
>>> b 
['apples', 'bananas', 'apples', 'bananas'] 
>>> a is b 
True 
>>> 
0

그것은 새로운 목록 개체를 만들지 않습니다, 그것은 a 확장 과도한 복제를 방지하기 위해 확장 될 때 여분의 공간이 할당되어 볼 수 있습니다. 이것은 당신이 부양을하지 않는다는 사실로부터 자명합니다. 파이썬은 당신의 객체를 마술처럼 다른 객체로 대체하지 않습니다.:-)

목록 개체 내에서 메모리 할당이 어떻게 발생하는지는 구현에 따라 다릅니다.