(Though it's really a pretty tiny library that just does what it says on the tin, not sure how many questions there can be. :D )
In fact, you write all of your python like you really have something to hide ;) Like `_Todo`.
Where did you get this pattern?
(I’m way more curious than accusatory. Are people embracing private modules these days as a convention, and I just missed it?)
I honestly love when I see a package do stuff like this: it's very clear then what is public interface, and I should consider usable (without sin) and what is supposed to be an internal detail.
Same with the modules: then it is very clear that the re-export of those names in __init__.py is where they're meant to be consumed, and the other modules are just for organizational purposes, not API purposes.
_Todo is then a private type.
Very clean.
from ._core import (
Loop as Loop,
sleep as sleep,
...
)
Does using `<name> as <name>` change the runtime behaviour at all? Or is it a stylistic choice?C.f. "the intention here is that only names imported using the form X as X will be exported" from PEP484. [1]
I'm generally a fan of the style of putting all the implementation in private modules (whose names start with an underscore) and then using __init__.py files solely to declare the public API.
I have a function I want to be a coroutine, but it has zero yield statements, so it is just a normal function?
You can distinguish it from a normal Python function by putting if False: yield somewhere inside its body. Another common trick is to put a yield statement after the final return statement. Bit ugly but oh well.
I'm fairly unfamiliar with python and I don't quite understand what this is actually doing. Does it change anything in the execution or is it just to mark it in a way for IDEs to do something with? >>> def foo_function():
... print('In a function!')
... return
...
>>> foo_function()
In a function!
And here's defining and calling a generator: >>> def foo_generator():
... print('In a generator!')
... return
... yield
...
>>> foo_generator()
<generator object foo_generator at 0x10321aa40>
>>> next(foo_generator())
In a generator!
Traceback (most recent call last):
File "<python-input-6>", line 1, in <module>
next(foo_generator())
~~~~^^^^^^^^^^^^^^^^^
StopIteration
Notice that the generator's body isn't evaluated until you consume the generator. StopIteration isn't actually an error in usual cases. It just says that the generator doesn't have any more values to return and has exited. For example, that's how Python's for-loop works: >>> for _ in foo_generator():
... continue
...
In bar!
Here it executes the generator's body (including the print() call) until it gets to the return statement. Because it's a generator, it returns as normal and then raises a StopIteration exception, which tells the loop to stop looping.
codethief•8h ago
Why, though?
dmerrick•7h ago
halfcat•7h ago
> ”Ever used asyncio and wished you hadn't?”
Yes, that’s me. I always found the yield-based approach to coroutines much easier to reason about. It’s just a generator function.