On Wed, May 27, 2020 at 05:03:09AM +1000, Chris Angelico wrote: > def foo(): > if False: x = 0 > # what is x now? > > There is no *value* in x, yet x has a state.
In Python code, no, it has no state, it's just an unbound name. That's literally a name that has nothing bound to it, hence no state. In the CPython 3 implementation, it has a hidden state: there's a fixed array representing the locals, one of those array slots represents x, and there is some kind of C-level special state to distinguish between "this slot is filled" and "this slot is not filled". But that's purely an optimization. Locals can also be backed by a dict, like globals. That is what happens in Jython, so when you call locals() you get back the actual local namespace dict and modifications to the variables works. (Unlike in CPython.) # Jython 2.7 >>> def test(): ... locals()['x'] = 999 ... if False: ... # Fool the compiler into treating x as a local. ... x = None ... print(x) ... >>> test() 999 IronPython appears to be different yet again, but I don't understand what it is doing so I can't explain it. In CPython 2, some locals were backed by the fast array slots, some were not. I think (but I'm not sure!) that if the compiler saw an exec or a star import inside a function, it switched off the fast array optimization. Or something like that. The bottom line here is that the Python execution model has names. Names can be bound to a value (an object), or they can be unbound in which case they have no state *in Python*. Whether that unboundness is represented by a nil pointer or a special magic value or is a consequence of a key being missing from a namespace dict is part of the implementation, not part of the Python semantics. > So we could have some > kind of definition of optional parameters where, rather than receiving > a default, they would simply not be bound. We could have an `if undef` keyword :-) if undef x: x = something (Not entirely serious about this proposal.) > def foo(?x): > # what is x? > > There would want to be a new way to query this state, though, because > I think this code is ugly enough to die: > > def foo(?x): > try: > x > except UnboundLocalError: > ... # do this if x wasn't passed in > else: > ... # do this if we have a value for x There's always: if 'x' in locals() > (It's probably best to define this ONLY for local variables. Module or > class name bindings behave differently, so they would simply never be > in this unbound state. Of course they are! # Module level state. x = None; del x # Ensure x is unbound. print(x) I frequently write top-level module code that tests for the existence of a global or builtin: try: spam except NameError: def spam(): ... That could become: if undef spam: def spam(): ... I would be cross if `if undef` worked inside functions but not globally. -- Steven _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@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/RG2JDSOYQXYRLRIZN5UVAPS5MDEHMGF4/ Code of Conduct: http://python.org/psf/codeofconduct/