6

Initially (PEP 380), yield from syntax was introduced to be used for delegating to a "subgenerator." Later it was used with now deprecated generator-based coroutines.

I cannot find out what kind of objects yield from can be applied to in general. My first conjecture was that it only requires __iter__ method on the object to return an iterator. Indeed, the following works with 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)))

However, it also works with some awaitables, like asyncio.sleep(1), which do not have __iter__ method.

What is the general rule? What determines if an object can be given as an argument to yield from form?

asked May 20, 2020 at 13:36
13
  • You are in the right path, but perhaps yield from asyncio.sleep(1) is confusing you. yield from is Python's 3.4 syntax equivalent of Python 3.5 await. Check out the documentation for Python 3.4 asyncio: 18.5.9.3. Concurrency and multithreading. Commented May 20, 2020 at 13:48
  • @Felipe, do you mean that yield from has two completely unrelated meanings? Does it have just two of them, or more? In the code example that i gave, you cannot replace yield from with await, so they are not always equivalent. Commented May 20, 2020 at 14:20
  • @Felipe, i do not see where in the documentation you pointed to my question is answered. Commented May 20, 2020 at 14:22
  • The first paragraph on the link documentation above. "An event loop runs in a thread and executes all callbacks and tasks in the same thread. While a task is running in the event loop, no other task is running in the same thread. But when the task uses yield from, the task is suspended and the event loop executes the next task." Commented May 20, 2020 at 14:35
  • Asynchronous programming is a different concept all together in Python (different from generators). In today's world, you use the keyword await to utilize asynchronous functions, but back before 3.4, you would use yield from as opposed to await (which is why you might see yield from sprinkled around in code that does not seem to have generators). Commented May 20, 2020 at 14:38

1 Answer 1

3

You can check how CPython evaluates that statement. From this follows it needs to be either a coroutine or an 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();
}
answered May 20, 2020 at 14:56
Sign up to request clarification or add additional context in comments.

3 Comments

So, there are really two unrelated meanings... Do you know if it was always so, or if historically all coroutines, including asyncio.sleep, had __iter__ method?
@Alexey Back then there was no real difference between coroutines and generators. As the 3.4 docs read: "A coroutine is a generator that follows certain conventions.". No separate coroutine type existed. PEP 492 which describes the change to async and await syntax is also informative with respect to the old behavior. PEP 3156 also provides information on that topic (e.g. search for yield from in these docs, it's a long read).
I wanted to see how concurrency was implemented with generators, but apparently it is too late, as the implementation changed. I would have to downgrade to Python 3.3, i suppose.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.