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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/RG2JDSOYQXYRLRIZN5UVAPS5MDEHMGF4/
Code of Conduct: http://python.org/psf/codeofconduct/