A plain async function pretty much IS a generator, but without the risk of removing the last await point and having the function stop being a generator. I am still lost in async space. From my initial benchmarking it seems that the complexity that async is introducing hardly justifies itself in performance. In other words, if it is done using `async` it’s performance is very similar to `gevent`, meaning, that all that hassle doesn’t justify itself in performance space, which is one of the major selling points.
If async is done with `yield`, then it could potentially be justified in performance-critical applications. I am not 100% certain about this as I haven't compared everything thoroughly, but these were the findings from my initial fairly crude testing. Am I missing something here?
But async generators are also a thing, and there's no easy way to make a generator-generator with two different types of yield in it. I’d rather not have 2nd yield and have things a bit simpler in that space...
On 18 Jul 2023, at 17:06, Chris Angelico <rosuav@gmail.com> wrote:
On Tue, 18 Jul 2023 at 23:41, Stephen J. Turnbull <turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
2. Comparing floats, even against zero, is a bad idea. So I would wrap them in math.isclose:
val = a ? (not isclose(c, 0) ? c : d) : (not isclose(d, 0) ? d : c)
That's overly simplistic; there are a lot of times when it's absolutely fine to compare floats for equality, particularly with zero, where the idea of "close" can be ill-defined. But this is the difficulty with toy examples - we have no idea how realistic this actually is. For now, though, I'd be inclined to keep the semantics unchanged and just look at the syntax.
In general you will have function calls adding parentheses -- and thus confusion. Perhaps there will be lists or tuples involved. You can precompute them and assign them to short name variables, but then you lose the one-liner-ness.
This is true, almost trivially so; one-liners aren't all that common because real-world use-cases are often complicated. However, they DO exist. It'd be nice to have really good examples but we may well not have that luxury.
3. OK, how about ints then? Yes, that would work, but how frequently are you going to be comparing against 0? Here's a more realistic case, with readable short argument names:
def clamp_int(n: int, lo: int, hi: int): # I wouldn't elide this test because if lo > hi you get a # plausible but necessarily erroneous value if lo > hi: raise ValueError(f'lo = {lo} > {hi} = hi') val = n < lo ? lo : (n > hi ? hi : n) return val
Agreed, the expression using Python's syntax would be worse, but I think this is much more readable:
def clamp_int(n: int, lo: int, hi: int): if lo > hi: raise ValueError(f'lo = {lo} > {hi} = hi') if n < lo: val = lo elif n > hi: val = hi else: val = n return val
and it would be more readable yet if you got rid of the assignments and just returned the value as soon as you see it:
def clamp_int(n: int, lo: int, hi: int): if lo > hi: raise ValueError(f'lo = {lo} > {hi} = hi') # Hi, David! Default first!! if lo <= n <= hi: # Yes, Virginia, valid Python! return n elif n > hi: return hi else: return lo
(Yes, I know that some folks argue that suites should have one entry point and one exit point, but I don't think it's a problem here because of the extreme symmetry and simplicity of the conditional. IMHO YMMV of course)
def clamp_int(n: int, lo: int, hi: int): if lo > hi: raise ValueError(f'{lo = } > {hi = }') return max(lo, min(n, hi))
Nobody said we weren't allowed to use builtins, right? :)
Now, you can add a new one that does the same thing, and that's been done. IIRC it took a while to get +=
Note that augmented operators are not simply shorthands for the expanded version. There are a few differences between:
a.b.c.d.e += value
and
a.b.c.d.e = a.b.c.d.e + value
including that the basis object (a.b.c.d) would only be evaluated once, and especially, the addition is done in-place if supported (eg with lists).
and C-like ++/-- increment operators have been requested over and over again. AFAIK the async syntaxes do nothing that can't be done with generators, but they make it a lot easier to do it right in the most common cases.
A plain async function pretty much IS a generator, but without the risk of removing the last await point and having the function stop being a generator. But async generators are also a thing, and there's no easy way to make a generator-generator with two different types of yield in it.
But yes, in general, these aren't drastically new pieces of functionality - they're nice improvements to readability and expressiveness. I can write an application that uses generators instead of async functions (and my current flagship non-Python project does exactly that), as long as I'm not using generators for anything else. I can write something with no augmented assignment operators, as long as I always use list extend instead of addition, and don't mind the reevaluation of intermediate components (which, most of the time, is only a performance matter, not a correctness one). But it's definitely nice to have them.
ChrisA _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/4A2NOU... Code of Conduct: http://python.org/psf/codeofconduct/