Home > OS >  Why add key in locals actually create variable?
Why add key in locals actually create variable?

Time:03-14

I tried to create a variable with spaces in the name, and I came up with this:

>>> classic_var = 'spam'
>>> locals()['classic_var'] 
'spam'
>>> classic_var
'spam'
>>> locals()['local_var'] = 'eggs'
>>> locals()['local_var'] 
'eggs'
>>> local_var
'eggs'
>>> locals()['variable with space in names'] = 'parrot'
>>> locals()['variable with space in names']
'parrot'

But someone replied that (source):

The dictionary returned by locals() just represents the entries in the local symbol table, these are not the symbols themselves. So changing this dictionary does not create any variable at all. See here: https://docs.python.org/3/library/functions.html#locals

So I wonder why does this works:

>>> a = 'test'
>>> locals()['a'] = 'hello'
>>> locals()['b'] = 'world'
>>> print(a, b)
hello world

Inside a function, locals modification doesn't works, but with globals(), same behavior.

The documentation says: "changes may not affect the values of local and free variables used by the interpreter". "may". But what is the condition? why it "may"? Under what circumstance?

This isn't for professionnal project, just research about how python works and how we can tweak things to create wierd things.

CodePudding user response:

This line from the documentation is important here:

Note that at the module level, locals() and globals() are the same dictionary.

Because you are not inside a function, you actually get the dictionary of the global variables of the interactive session.

So something like locals()['a'] = 'hello' actually creates a new global variable a, and that's perfectly fine in Python, because global variables work differently than local variables.

If you try something like:

def test():
    global global1
    local1 = 'hi'
    global1 = 'ok'
    print(locals())

test()

It only shows {'local1': 'hi'}.

If you tried:

def test():
    locals()['local2'] = 'hello world'
    print(local2)

test()

You would get a name error that local2 is not defined.

CodePudding user response:

If you read the actual documentation, you'll see the following:

Note: The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

The documentation makes no promises about what modifying the dictionary will do.


locals() is really weird. It's not just the fact that changing the dictionary has inconsistent effects on local variables - changing local variables has inconsistent effects on the dictionary.

At global scope, or in a class statement, the dictionary locals() returns is the actual canonical representation of the local scope. Changing the dictionary will change variables in that scope, and assigning variables will change the dictionary.

At function scope, the dictionary locals() returns is not the primary representation of the local scope. It's a separate dictionary attached to the stack frame. Calling locals() updates that dictionary with the current values of local variables and returns the dictionary.

At function scope, changing the dictionary will usually not update local variables, but in some special circumstances (mostly related to debugging), Python will copy values from the dictionary back to local variables.

At function scope, changing local variables will usually not update the dictionary, unless you call locals() again or something accesses the frame object's f_locals attribute. Debuggers access f_locals to read local variable values, so code that uses locals() will often break in a debugger if it's not written to handle this:

>>> def f():
...     x = 1
...     y = locals()
...     x = 2
...     print(y['x'])
... 
>>> f()
1
>>> def f():
...     x = 1
...     y = locals()
...     x = 2
...     breakpoint()
...     print(y['x'])
... 
>>> f()
> <stdin>(6)f()
(Pdb) n
2

Here, adding a breakpoint causes the function to print 2 instead of 1.

  • Related