web-dev-qa-db-ja.com

「yield from」で使用できるオブジェクトの種類は何ですか?

当初( PEP 38 )、_yield from_構文は、「サブジェネレータ」への委任に使用す​​るために導入されました。後でそれは現在 非推奨 ジェネレータベースのコルーチンで使用されました。

一般的にどのような種類のオブジェクト_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)))
_

ただし、___iter___メソッドを持たないasyncio.sleep(1)などの一部のawaitableでも機能します。

一般的なルールは何ですか?オブジェクトを_yield from_フォームへの引数として与えることができるかどうかを決定するものは何ですか?

6
Alexey

CPython そのステートメントを評価する方法 を確認できます。これからは、コルーチンまたはイテラブルのいずれかである必要があります。

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();
}
2
a_guest