[Python]Extended Iterable Unpacking
서론
네이버 블로그에서 velog로 옮기면서 괜찮은 내용이거나 아니면 한번 더 살펴봐야할 포스팅을 옮기게 되었다
이 글에서는 pep 3132에 대해서 다룬다.
해당 내용은 순환 가능 요소의 언패킹에 *(star-expr)를 사용하는 것을 권장하는 이유에 대해서 설명한다.
문제점
언패킹에 있어서 많은 알고리즘에서 기존에 사용하는 방식은 아래와 같았다.
first, last = seq[0], seq[1:]
위의 방식처럼 index를 이용한 slicing 방법을 사용했지만 이는 다음과 같은 문제점이 있었다.
- 셋과 같이 리스트는 아니지만 순회 가능한 요소의 경우 다음과 같은 과정을 거쳐야해서 성능을 저하시켰다.
it = iter(seq)
first = it.next()
rest = list(it)
- 불필요한 인덱싱을 사용해야 한다.
권장 사용
위의 문제점을 해결하기 위한 방법으로 아래와 같은 방식을 권장한다.
first, *last = seq
# 아래와 같은 방식도 가능
a, * b, c = seq
[a, * b, c] = seq
* a, = seq
a, * b in [(1, 2, 3), (4, 5, 6, 7)]:
print (b)
# 불가능한 방식
* a = seq # 단일 사용
*를 사용하면 아래와 같은 방식으로 동작한다.
- all items for mandatory targets before the starred one
- collect all remaining items from the iterable in a list
- pop items for mandatory targets after the starred one from the list
- push the single items and the resized list on the stack
위의 설명대로 예시를 들자면 아래의 코드를 실행했을 때:
a, *b, c = [1, 2, 3, 4, 5]
다음과 같이 동작한다.
a = 1
b = [2, 3, 4, 5]
c = b.pop()
정확한 동작 소스 코드(CPython)
unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
{
int i = 0, j = 0;
Py_ssize_t ll = 0;
PyObject *it; /* iter(v) */
PyObject *w;
PyObject *l = NULL; /* variable list */
assert(v != NULL);
it = PyObject_GetIter(v);
if (it == NULL)
goto Error;
for (; i < argcnt; i++) {
w = PyIter_Next(it);
if (w == NULL) {
/* Iterator done, via error or exhaustion. */
if (!PyErr_Occurred()) {
if (argcntafter == -1) {
PyErr_Format(PyExc_ValueError,
"not enough values to unpack (expected %d, got %d)",
argcnt, i);
}
else {
PyErr_Format(PyExc_ValueError,
"not enough values to unpack "
"(expected at least %d, got %d)",
argcnt + argcntafter, i);
}
}
goto Error;
}
*--sp = w;
}
if (argcntafter == -1) {
/* We better have exhausted the iterator now. */
w = PyIter_Next(it);
if (w == NULL) {
if (PyErr_Occurred())
goto Error;
Py_DECREF(it);
return 1;
}
Py_DECREF(w);
PyErr_Format(PyExc_ValueError,
"too many values to unpack (expected %d)",
argcnt);
goto Error;
}
l = PySequence_List(it);
if (l == NULL)
goto Error;
*--sp = l;
i++;
ll = PyList_GET_SIZE(l);
if (ll < argcntafter) {
PyErr_Format(PyExc_ValueError,
"not enough values to unpack (expected at least %d, got %zd)",
argcnt + argcntafter, argcnt + ll);
goto Error;
}
/* Pop the "after-variable" args off the list. */
for (j = argcntafter; j > 0; j--, i++) {
*--sp = PyList_GET_ITEM(l, ll - j);
}
/* Resize the list. */
Py_SIZE(l) = ll - argcntafter;
Py_DECREF(it);
return 1;
Error:
for (; i > 0; i--, sp++)
Py_DECREF(*sp);
Py_XDECREF(it);
return 0;
}
고찰
unpack_iterable(PyObject *v, int argcnt, int argcntafter, PyObject **sp)
{
int i = 0, j = 0;
Py_ssize_t ll = 0;
PyObject *it; /* iter(v) */
PyObject *w;
PyObject *l = NULL; /* variable list */
assert(v != NULL);
it = PyObject_GetIter(v);
if (it == NULL)
goto Error;
for (; i < argcnt; i++) {
w = PyIter_Next(it);
if (w == NULL) {
/* Iterator done, via error or exhaustion. */
if (!PyErr_Occurred()) {
if (argcntafter == -1) {
PyErr_Format(PyExc_ValueError,
"not enough values to unpack (expected %d, got %d)",
argcnt, i);
}
else {
PyErr_Format(PyExc_ValueError,
"not enough values to unpack "
"(expected at least %d, got %d)",
argcnt + argcntafter, i);
}
}
goto Error;
}
*--sp = w;
}
if (argcntafter == -1) {
/* We better have exhausted the iterator now. */
w = PyIter_Next(it);
if (w == NULL) {
if (PyErr_Occurred())
goto Error;
Py_DECREF(it);
return 1;
}
Py_DECREF(w);
PyErr_Format(PyExc_ValueError,
"too many values to unpack (expected %d)",
argcnt);
goto Error;
}
l = PySequence_List(it);
if (l == NULL)
goto Error;
*--sp = l;
i++;
ll = PyList_GET_SIZE(l);
if (ll < argcntafter) {
PyErr_Format(PyExc_ValueError,
"not enough values to unpack (expected at least %d, got %zd)",
argcnt + argcntafter, argcnt + ll);
goto Error;
}
/* Pop the "after-variable" args off the list. */
for (j = argcntafter; j > 0; j--, i++) {
*--sp = PyList_GET_ITEM(l, ll - j);
}
/* Resize the list. */
Py_SIZE(l) = ll - argcntafter;
Py_DECREF(it);
return 1;
Error:
for (; i > 0; i--, sp++)
Py_DECREF(*sp);
Py_XDECREF(it);
return 0;
}
영어 공부 좀 하자..
Author And Source
이 문제에 관하여([Python]Extended Iterable Unpacking), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dj-yang/PythonExtended-Iterable-Unpacking저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)