for i in foo:
print i
이 코드는 실패한 코드이므로, 내부적으로 어떤 일이 발생하는지 살펴보고 일부 파이썬 내부 용 다이빙을 살펴 보겠습니다.
for i in foo
이 컴파일되면 생성 된 바이트 코드는 foo
을 반복 가능한 것으로 변환하는 GET_ITER
opcode를 포함하게됩니다. GET_ITER
은 iterable을 제공하는 실제 구현 인 객체에서 PyObject_GetIter
호출을 발생시킵니다. (당신이 적어도 몇 가지 기본적인 C를 이해한다면) 당신이 볼 수 있듯이, 기본 유형이 먼저 객체 (o->ob_type
)에서 조회됩니다
PyObject * PyObject_GetIter(PyObject *o)
{
PyTypeObject *t = o->ob_type;
getiterfunc f = NULL;
if (PyType_HasFeature(t, Py_TPFLAGS_HAVE_ITER))
f = t->tp_iter;
if (f == NULL) {
if (PySequence_Check(o))
return PySeqIter_New(o);
return type_error("'%.200s' object is not iterable", o);
}
else {
PyObject *res = (*f)(o);
if (res != NULL && !PyIter_Check(res)) {
PyErr_Format(PyExc_TypeError,
"iter() returned non-iterator of type '%.100s'",
res->ob_type->tp_name);
Py_DECREF(res);
res = NULL;
}
return res;
}
}
, 다음의 ITER 기능은 다음과 같습니다 그럼 what it does에서 살펴 보자 읽으십시오().
당신이 유형에 __iter__
기능을 구현하기 때문에,이 기능은 존재한다, 그래서 우리는 객체 o
에 iter
기능을 실행 위의 코드에있는 else
경우에 얻을. 결과는 null이 아니지만 "반복되지 않은 이터레이터"메시지가 표시되므로 PyIter_Check(res)
이 실패한 것처럼 보입니다. 그럼 what that does에서 살펴 보자 :
#define PyIter_Check(obj) \
(PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \
(obj)->ob_type->tp_iternext != NULL && \
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
그래서이 사람은 본질적으로 전달 된 객체의 유형 (ob_type
)을하지 될 일이없는 null 이외의 next
방법 (tp_iternext
)가있는 경우 확인 - 다음 기능을 구현했습니다.
확인 결과는 유형이 아니고 결과 자체가 아닙니다. foo
개체에는 next
함수가 있지만 해당 형식은 Foo
입니다.
setattr(foo, 'next', MethodType(next, foo, Foo))
... 이상 명시 적으로 ...
foo.next = next.__get__(foo, Foo)
는 ... 단지 유형 자체에 인스턴스에 바인딩 next
방법 을 설정하지만,하지 않습니다. 따라서 위의 C 코드는 iterable로 소비하지 못합니다.대신 유형에 next
기능을 설정한다면
, 그것을 잘 작동합니다 : classmethod
와 시도가 일을 왜
foo = Foo()
Foo.next = next
for i in foo:
print i
이는 이유입니다 : 당신은 유형의 기능을 설정 구체적인 인스턴스 대신
이 코드는 무엇을하기로되어 있습니까? – poke
다음 메소드를 iterator로 만들기 위해 동적으로 바인딩하고 싶습니다. – QuantumEnergy
일반적으로'__double_underscored__' 이름이지만 Python 2에서'next' (파이썬 3에서는'__next__ '로 이름이 바뀐)라는 특수 메소드는 인스턴스가 아니라 클래스에 정의되어야합니다. 예를 들어'__add__' 메서드를 동적으로 추가하면 비슷한 문제가 발생합니다. – Blckknght