The most confusing thing in Python is that there is more than one way to do it. :)
Python asyncio library supports coroutines, callbacks, futures, thread-pool executors... All have similar APIs and dissimilar semantics. For instance, canceling a coroutine is different than canceling a future and different than canceling a thread. (I've heard asynchronous exceptions are bad, but this is just an example.)
Error handling is difficult. You can't observe an error if you don't remember to write code to observe an error.
Also confusing is that coroutines in Python can be driven by any event loop. Which is great! You can write your own. But that will be even more confusing. Erlang has one OTP, Python will have many.
The most confusing thing in Python is that there is more than one way to do it. :)
Exactly. Python had a multiple thread and blocking I/O model. That's well understood. Javascript had a single thread callback-based model. That's well understood. When you have both concepts in the same system, things get much more complicated. It's even worse when it's a retrofit.
Consider Python's Queue module. If you call Queue.get(), your thread can block. But the async system doesn't understand that kind of block. (Is that right?) So you've blocked all the async stuff running off that thread.
Go has lightweight threads too, called goroutines. But because it wasn't a retrofit, all lock mechanisms are compatible with lightweight threads. When a goroutine blocks on a lock, its underlying thread is re-dispatched. Python 3.6 isn't set up that way, because async operations were retrofitted in parallel with the existing machinery.
Python asyncio library supports coroutines, callbacks, futures, thread-pool executors... All have similar APIs and dissimilar semantics. For instance, canceling a coroutine is different than canceling a future and different than canceling a thread. (I've heard asynchronous exceptions are bad, but this is just an example.)
Error handling is difficult. You can't observe an error if you don't remember to write code to observe an error.
Also confusing is that coroutines in Python can be driven by any event loop. Which is great! You can write your own. But that will be even more confusing. Erlang has one OTP, Python will have many.