如果我有一個列表:python如何擴展工作?
a = [1,2,3,4]
,然後使用加4元擴大
a.extend(range(5,10))
我得到
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Python是怎樣做到這一點?它是否會創建一個新列表並將這些元素複製到對象上,還是使它變得更大?只關心使用擴展會吞噬內存。我'還問,因爲在一些代碼,我修改,通過10000×100延伸比的1000000
如果我有一個列表:python如何擴展工作?
a = [1,2,3,4]
,然後使用加4元擴大
a.extend(range(5,10))
我得到
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Python是怎樣做到這一點?它是否會創建一個新列表並將這些元素複製到對象上,還是使它變得更大?只關心使用擴展會吞噬內存。我'還問,因爲在一些代碼,我修改,通過10000×100延伸比的1000000
L.extend(M)將攤銷爲O(n),其中n = LEN(米),因此,過度的,不能複製,通常的問題。 可能是一個問題的時間是當沒有足夠的空間擴展到,所以執行副本。當列表很大時,這是一個問題,並且您對單個擴展調用可接受的時間有限制。
這是您應該爲您的問題尋找更高效的數據結構的關鍵。我發現這在實踐中很少是問題。
這裏是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);
}
Python的documentation on it一塊做這件事更快評論說:
延長通過在給定列表中追加所有 項目;相當於
a[len(a):] = L
。
至於「如何」它在背景後面,你真的不需要關心它。
它的工作原理就好像這樣
def extend(lst, iterable):
for x in iterable:
lst.append(x)
這個變異的列表中定義的,它不創建一個副本。
根據底層的實現,append
和extend
可能會觸發列表來複制自己的數據結構,但這是正常的,沒有什麼可擔心的。例如,基於數組的實現通常會以指數形式增長底層數組,並且需要在它們這樣做時複製元素列表。
python如何做到這一點?它是否會創建一個新列表並將這些元素複製到對象上,還是使它變得更大?
>>> 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
>>>
它不創建一個新的列表對象,它擴展a
多餘的空間分配。這是不言而喻的,因爲你不做任何分配。 Python不會神奇地用其他對象替換你的對象。:-)
如何在列表對象內部發生內存分配取決於實現。
依賴於實現。 – 2011-03-03 04:32:32
感謝您的信息傢伙。 – Martlark 2011-03-03 05:44:05