TypeError: тип аргумент объекта после * должен быть последовательностью, а не генератором

Почему следующий код Python вызывает ошибку? TypeError: type object argument after * must be a sequence, not generator
в то время как если я прокомментирую первую (бесполезную) линию в генераторе f, все будет хорошо работать?

from itertools import izip

def z():
    for _ in range(10): 
        yield _

def f(z):
    for _ in z: pass    # if I comment this line it works! (??)
    for x in range(10):
        yield (x,10*x,100*x,1000*x)

iterators =  izip(*f(z))
for it in iterators:
    print list(it)

N.B. То, что я на самом деле пытаюсь сделать, - с одним генератором - возвращать несколько итераторов (столько, сколько я передам генератору в качестве аргументов). Единственный способ, которым я нашел это, - это получить кортежи и использовать izip() для них - черную магию для меня.

Ответ 1

Это забавно: вы забыли позвонить z, когда вы передали его на f:

iterators =  izip(*f(z()))

Итак, f попытался выполнить итерацию по объекту функции:

for _ in z: pass  # z is a function

Это вызвало TypeError:

TypeError: 'function' object is not iterable

Внутренние Python поймали его и сделали ререйз с запутанным сообщением об ошибке.

# ceval.c

static PyObject *
ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
{
 ...

            t = PySequence_Tuple(stararg);
            if (t == NULL) {
                if (PyErr_ExceptionMatches(PyExc_TypeError)) {
                    PyErr_Format(PyExc_TypeError,
                                 "%.200s%.200s argument after * "
                                 "must be a sequence, not %200s",
                                 PyEval_GetFuncName(func),
                                 PyEval_GetFuncDesc(func),
                                 stararg->ob_type->tp_name);
 ...