그것은 년대 groupby
때문에 개체가 부기를 처리하고 개체는 key
개체와 부모 개체 인 groupby
을 참조합니다.
typedef struct {
PyObject_HEAD
PyObject *it; /* iterator over the input sequence */
PyObject *keyfunc; /* the second argument for the groupby function */
PyObject *tgtkey; /* the key for the current "grouper" */
PyObject *currkey; /* the key for the current "item" of the iterator*/
PyObject *currvalue; /* the plain value of the current "item" */
} groupbyobject;
typedef struct {
PyObject_HEAD
PyObject *parent; /* the groupby object */
PyObject *tgtkey; /* the key value for this grouper object. */
} _grouperobject;
groupby
개체를 압축 해제 할 때 grouper
개체를 반복하지 않으므로 무시해 보겠습니다. 그래서 흥미로운 것은 당신이 그것에 next
를 호출 할 때 groupby
에서 일어나는 것입니다 :
static PyObject *
groupby_next(groupbyobject *gbo)
{
PyObject *newvalue, *newkey, *r, *grouper;
/* skip to next iteration group */
for (;;) {
if (gbo->currkey == NULL)
/* pass */;
else if (gbo->tgtkey == NULL)
break;
else {
int rcmp;
rcmp = PyObject_RichCompareBool(gbo->tgtkey, gbo->currkey, Py_EQ);
if (rcmp == 0)
break;
}
newvalue = PyIter_Next(gbo->it);
if (newvalue == NULL)
return NULL; /* just return NULL, no invalidation of attributes */
newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, newvalue, NULL);
gbo->currkey = newkey;
gbo->currvalue = newvalue;
}
gbo->tgtkey = gbo->currkey;
grouper = _grouper_create(gbo, gbo->tgtkey);
r = PyTuple_Pack(2, gbo->currkey, grouper);
return r;
}
내가 모든 관련이없는 예외 처리 코드 제거 또는 단순화 된 순수한 참조 카운팅 물건을 제거했습니다. 여기서 흥미로운 점은 gbo->currkey
, gbo->currvalue
및 gbo->tgtkey
이 이터레이터의 마지막에 도달하면 NULL
으로 설정되지 않고 PyIter_Next(gbo->it) == NULL
일 때 return NULL
이기 때문에 마지막으로 발생한 값 (반복기의 마지막 항목)을 계속 가리 킵니다. .
이 작업을 마친 후에는 두 개의 grouper
개체가 있습니다. 첫 번째 파일은 tgtvalue
이 False
이고 두 번째 파일이 True
입니다.당신이이 grouper
들에 next
를 호출 할 때의 어떤 일이 발생 살펴 보자 :
이
static PyObject *
_grouper_next(_grouperobject *igo)
{
groupbyobject *gbo = (groupbyobject *)igo->parent;
PyObject *newvalue, *newkey, *r;
int rcmp;
if (gbo->currvalue == NULL) {
/* removed because irrelevant. */
}
rcmp = PyObject_RichCompareBool(igo->tgtkey, gbo->currkey, Py_EQ);
if (rcmp <= 0)
/* got any error or current group is end */
return NULL;
r = gbo->currvalue; /* this accesses the last value of the groupby object */
gbo->currvalue = NULL;
gbo->currkey = NULL;
return r;
}
그래서 currvalue
이 하지NULL
, 그래서 첫 번째 if
가지 재미없는 기억. 귀하의 첫 번째 그룹에 대해 그것은 grouper
과 groupby
개체의 tgtkey
을 비교하여 서로 다르다는 것을 확인하고 즉시 return NULL
이됩니다. 그래서 빈 목록이 있습니다. tgtkey
S가 동일한 제 2 반복자
, 그래서
groupby
객체 (이터레이터 마지막 발생 값인!)의
currvalue
을 반환하지만, 이번에는
currvalue
및
currkey
의 설정 것
groupby
의 개체는
NULL
입니다.
g1
의 한 요소가 속하지 않은
import itertools
>>> inputs = [(x > 5, x) for x in range(10)] + [(False, 10)]
>>> (_, g1), (_, g2), (_, g3) = itertools.groupby(inputs, key=lambda x: x[0])
>>> list(g1)
[(False, 10)]
>>> list(g3)
[]
그건 : 파이썬으로 다시 전환
는
: 당신이 당신의 groupby
의 마지막 그룹과 같은 tgtkey
와 grouper
을하면 정말 재미있는 단점이 발생 첫 번째 그룹화 객체의 tgtkey
이 False
이고 마지막 tgtkey
이 False
이므로 첫 번째 그룹은 첫 번째 그룹이 첫 번째 그룹에 속한다고 생각했습니다. 또한 groupby
개체를 무효화하여 세 번째 그룹이 비어있게되었습니다.
모든 코드는 the Python source code에서 가져 왔지만 짧아졌습니다.
PyPy를 CPython처럼 동작하도록 변경했습니다. 필자는 이것이 왜 "왜"라는 질문에 실제로 대답하지 않는다는 것을 알고 있습니다. docy에서 재구성 된 버전을 사용하는 대신 CPython에서 정확한 알고리즘을 PyPy로 복사하는 것만으로도 동일한 결과를 얻을 수 있습니다. –
동작이 약간 손상된 것 같습니다. CPython 문제 보고서에서이 질문을하고 싶을 것 같습니다. 아마 다음 3.7 릴리스에서 수정 될 것입니다. 또는 어쩌면 누군가 현재의 행동이 더 나은 이유에 대한 이유를 발견 할 것입니다. 또는 귀하의 문제는 영원히 열려있을 것입니다. –
관심있는 다른 사람들을 위해 [이 커밋] (https://bitbucket.org/pypy/pypy/commits/6093ff1a44e6b17f09db83aa80aea562a738c286)에서 변경된 pypy처럼 보입니다. – mgilson