On 18 April 2015 at 16:05, Andrew Barnert firstname.lastname@example.org wrote:
On Apr 17, 2015, at 21:48, Rustom Mody email@example.com wrote:
On Sat, Apr 18, 2015 at 12:28 AM, Yury Selivanov firstname.lastname@example.org wrote:
Here's my proposal to add async/await in Python.
I believe that PEPs 380 and 3156 were a major breakthrough for Python 3,
I am also interested in this topic --- from the other side. As a teacher of python it is my finding that the terminology/documentation around generators is rather chaotic and messy. Basically given: def foo(): yield 1 bar = foo()
what do we call foo and what do we call bar? It is suggested that foo is "generator-function" and bar is "generator-object" Unfortunately python does not aid this distinction; witness
... yield 1 ...
bar = foo() type(foo)
I assume you're ok with the type(bar); the type of a generator object is named "generator", just like the type of a bound method object is named "method" and the type of an integer object is named "int", and so on.
So presumably you don't like the former. But what about it?
The only thing I can imagine is the fact that, even though a generator function is conceptually a "subkind" of function, there is no generator function subtype of the function type?
But so what? There's no closure function subtype, just functions whose closure is nonempty; there's no positive int subtype, just ints whose value is positive; etc. And likewise, there's no callable supertype that function and method (and other things) inherit.
If there were some additional API that a generator function should provide that other functions don't (or some implementation reason that makes it worth subclassing for convenience, I suppose), that would be a good reason for needing a subtype. For example, generator a subtype of iterator, just as file is, because they both add new methods that don't make sense for the base iterator type.
But just wanting repr(type(x)) to give you more information about x, that's not a good reason to add a subtype.
So, it seems to me like both of these are returning something you should reasonably expect.
Catching up on email following PyCon travel, there's a reasonable question here related to the repr() of "foo" itself:
>>> def foo(): ... yield 1 ... >>> foo <function foo at 0x7f7dad9f7bf8> >>> import dis >>> dis.show_code(foo) Name: foo Filename: <stdin> Argument count: 0 Kw-only arguments: 0 Number of locals: 0 Stack size: 1 Flags: OPTIMIZED, NEWLOCALS, GENERATOR, NOFREE Constants: 0: None 1: 1
Modifying the repr of a function based on whether or not the GENERATOR flag was set on the code object would be quite doable. For example, the above could be:
>>> foo <function foo at 0x7f7dad9f7bf8 (generator)>
type(foo) would still be unchanged, we'd just be exposing some additional info in the value repr().
While it's a less significant behavioural difference than being a generator function, a non-empty closure could conceivably also be reported in the repr():
<function foo at 0x7f7dad9f7bf8 (closure)> <function foo at 0x7f7dad9f7bf8 (closure,generator)>