It yields *and* returns, that's the way Guido's API works (as I understand it).
I can't speak for Guido obviously, but you've certainly described what we came up with perfectly (http://pastebin.com/ndS53Cd8, the _Awaiter class starts on line 93).
# The real kicker here? Replace "yield wait_for_page" with "wait_for_page.result()" and you have the equivalent concurrent.futures code.
Basically, the task/tasklet/async decorator aggregates the futures from inside the wrapped method and exposes a single future to the caller. Your example doesn't even need a scheduler or event loop, and we found that all the event loop was really doing was running the callbacks in a certain thread/context/equivalent. And because there is a future coming out of every call, the user can choose when to stop using tasklets and go back to using plain old futures (or whatever subclasses have been used).