New submission from wang xuancong <xuancon...@gmail.com>:

In general, the ability to update local variables is very important and it 
simplifies life tremendously. For example, in machine learning, it allows 
saving/loading arbitrary-format datasets and arbitrary-structure neural 
networks (NN) using a single line of code. In computer games, no matter how 
many complex data structures are there, saving and loading can be done in a 
single line.

Imagine you are game developer or a deep neural network (DNN) researcher, if 
all local variables are serializable, then no matter how complicated your game 
or your DNN structure is, saving the entire game or DNN (to STDOUT) can be 
simply put into one line as `print(locals())`, and loading the entire game or 
DNN (from STDIN) can be simply put into one line as 
`locals().update(eval(sys.stdin.read()))`.

Currently, `globals().update(...)` takes immediate effect but 
`locals().update(...)` does not work because Python documentation says:

> The default locals act as described for function locals() below:
> modifications to the default locals dictionary should not be
> attempted. Pass an explicit locals dictionary if you need to see
> effects of the code on locals after function exec() returns.

Why they design Python in such way is because of optimization and conforming 
the `exec` statement into a function:

> To modify the locals of a function on the fly is not possible without
> several consequences: normally, function locals are not stored in a
> dictionary, but an array, whose indices are determined at compile time
> from the known locales. This collides at least with new locals added
> by exec. The old exec statement circumvented this, because the
> compiler knew that if an exec without globals/locals args occurred in
> a function, that namespace would be "unoptimized", i.e. not using the
> locals array. Since exec() is now a normal function, the compiler does
> not know what "exec" may be bound to, and therefore can not treat is
> specially.

Since `global().update(...)` works, the following piece of code will work in 
root namespace (i.e., outside any function) because locals() is the same as 
globals() in root namespace:
```
locals().update({'a':3, 'b':4})
print(a, b)
```
But this will not work inside a function.

I have explored a few ways of hacking updating locals() on Python 3, it seems 
there is no way so far. The following piece of code seems to works:
```
def f1():
  sys._getframe(1).f_locals.update({'a':3, 'b':4})
  print(a, b)

f1()
```
However, that is because `sys._getframe(1)` is the root namespace, so 
`sys._getframe(1).f_locals.update()` is essentially `globals().update()`.

>From the above Python developer documentation, I understand that in Python 2, 
>local namespace lookup has 2 modes: optimized mode if there is no `exec` 
>statement, un-optimized mode if there exists an `exec` statement. But in 
>Python 3, `exec` becomes a function, so the compiler cannot determine which 
>namespace optimization mode at compile time (because `exec` can be overridden 
>or aliased into a different name). Therefore, Python 3 has only optimized 
>namespace lookup. My suggestion is that whenever this optimized local 
>namespace lookup fails, perform an un-optimized lookup (which will include 
>locals()). This should solve the problem.

Do you have any other ideas or suggestions for doing this? Thanks!

----------
components: Interpreter Core
messages: 392852
nosy: xuancong84
priority: normal
severity: normal
status: open
title: Request for locals().update() to work, it is
type: enhancement
versions: Python 3.11

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue44028>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to