"yield from "可以用于什么样的对象?

问题描述 投票:6回答:1

最初(PEP 380), yield from 语法被引入,用于委托给 "子生成器"。后来它与现在的 弃用 基于生成器的coroutines。

我找不到什么样的对象 yield from 可以适用于一般情况。我的第一个猜想是,它只需要 __iter__ 方法来返回一个迭代器。事实上,下面的内容在Python 3.8中是可行的。

class C:
    def __init__(self, n):
        self.n = n

    def __iter__(self):
        return iter(range(self.n))

def g(n):
    yield from C(n)

print(tuple(g(3)))

然而,它也适用于一些可等待的对象,如 asyncio.sleep(1),其中没有 __iter__ 方法。

一般规则是什么?是什么决定了一个对象是否可以作为参数给 yield from 的形式?

python python-3.x generator coroutine yield-from
1个回答
2
投票

你可以查看CPython是如何 评估该语句. 由此可见,它需要是一个coroutine或者是一个iterable。

case TARGET(GET_YIELD_FROM_ITER): {
    /* before: [obj]; after [getiter(obj)] */
    PyObject *iterable = TOP();
    PyObject *iter;
    if (PyCoro_CheckExact(iterable)) {
        /* `iterable` is a coroutine */
        if (!(co->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
            /* and it is used in a 'yield from' expression of a
               regular generator. */
            Py_DECREF(iterable);
            SET_TOP(NULL);
            _PyErr_SetString(tstate, PyExc_TypeError,
                             "cannot 'yield from' a coroutine object "
                             "in a non-coroutine generator");
            goto error;
        }
    }
    else if (!PyGen_CheckExact(iterable)) {
        /* `iterable` is not a generator. */
        iter = PyObject_GetIter(iterable);
        Py_DECREF(iterable);
        SET_TOP(iter);
        if (iter == NULL)
            goto error;
    }
    PREDICT(LOAD_CONST);
    DISPATCH();
}
© www.soinside.com 2019 - 2024. All rights reserved.