On Thu, Mar 9, 2017 at 3:04 AM, Matthias Urlichs <sm...@noris.de> wrote:
> Is this pattern > > def foo(): > return bar() > async def bar(): > await <whatever> > > async def async_main(): > await foo() > > considered to be valid? > Yes, it is valid. > The reason I'm asking is that some code out there likes to accept a > might-be-a-coroutine-function argument, using > > def run_callback(fn): > if iscoroutinefunction(fn): > res = await fn() > else: > res = fn() > > instead of > > def run_callback(fn): > res = fn() > if iscoroutine(res): > res = await res() > > The former obviously breaks when somebody combines these idioms and calls > > run_callback(foo) > > but I can't help but wonder whether the latter use might be deprecated, or > even warned about, in the future and/or with non-CPython implementations. > In general I would recommend against patterns that support either awaitables or non-awaitables. The recommended solution is for run_callback() to require an awaitable, and if you have a function that just returns the value, you should wrap it in an async def that doesn't use await. The difference between the two versions of run_callback() is merely the difference you pointed out -- iscoroutinefunction(f) is not entirely equivalent to iscoroutine(f()). If you're thinking in terms of static types (e.g. PEP 484 and mypy), in the latter version the type of `res` is problematic (it's Union[Awaitable[T], T]), but there's an easy way to rewrite it to avoid that, while still calling iscoroutine(). If there's something else you worry about with the latter please clarify. But in general I would stay far away from this kind of "do what I mean" API -- they are hard to reason about and difficult to debug. -- --Guido van Rossum (python.org/~guido)
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com