Yield after the return in Python function.

Chris Angelico rosuav at gmail.com
Mon Apr 5 15:32:25 EDT 2021


On Tue, Apr 6, 2021 at 5:14 AM Terry Reedy <tjreedy at udel.edu> wrote:
>
> On 4/5/2021 1:53 PM, Chris Angelico wrote:
> > On Tue, Apr 6, 2021 at 3:46 AM Terry Reedy <tjreedy at udel.edu> wrote:
> >> *While 'a and not a' == False in logic, in Python it might raise
> >> NameError.  But that would still mean that it is never True, making
> >> 'yield 0' still unreachable.
>
> When I wrote that, I knew I might be missing something else.
>
> > And even just the lookup can have side effects, if your code is
> > pathologically stupid.
>
> Or pathologically clever.
>
> >>>> class Wat(dict):
> > ...     def __missing__(self, key):
> > ...             global count
> > ...             count -= 1
> > ...             return count
>
> '__missing__' is new since I learned Python.  I barely took note of its
> addition and have never used it.  Thanks for the example of what it can
> do.  One could also make it randomly return True or False.

Yep. It could be done with a __getitem__ method instead; the point is
that simply looking up a simple name can have side effects and/or be
nondeterministic.

> >>>> count = 2
> >>>> eval("print(a and not a)", Wat(print=print))
> > True
> >
> > So Python can't afford to treat this as dead code.
>
> This gets to the point that logic and math are usually atemporal or at
> least static (as in a frozen snapshot), while computing is dynamic.  In
> algebra, the canon is that all instances of a variable are replaced by
> the same value.

Right - or rather, that in algebra, a "variable" is really a
placeholder for a single, specific value, which may perhaps be unknown
to us, but which has a very well-defined value.

(At least, that's the case with most values, and with a convergent
series. Things can break down a bit with a divergent series, but even
then, analytic continuation can sometimes give you a well-defined
value.)

> Python *could* do the same for expresssions: load 'a' (in this case)
> once into a register or stack slot and use that value consistently
> throughout the expression.  Replacing the eval with the following exec
> has the same effect.

True, but I think that this would be enough of a semantic change that
Python should be very VERY careful about doing it. A *programmer* can
choose to do this (and we see it sometimes as an optimization, since
global lookups can be a lot more costly), but the interpreter
shouldn't.

> exec("tem=a; print(tem and not tem)", Wat(print=print))
> # print False
>
> In this example, one could disable the binding with __setitem__
> (resulting in printing 0), but python code cannot disable internal
> register or stack assignments.
>

Indeed. That said, though, I think that any namespace in which
referencing the same simple name more than once produces this sort of
bizarre behaviour should be considered, well, unusual. NORMAL code
won't have to concern itself with this. But the language spec doesn't
require us to write normal code......

ChrisA


More information about the Python-list mailing list