On Tue, Apr 6, 2021 at 5:14 AM Terry Reedy <tjre...@udel.edu> wrote: > > On 4/5/2021 1:53 PM, Chris Angelico wrote: > > On Tue, Apr 6, 2021 at 3:46 AM Terry Reedy <tjre...@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 -- https://mail.python.org/mailman/listinfo/python-list