Why is it bad idea to modify locals in python?
Asked Answered
K

5

11

Related to this reply here. Locals' doc here.

The docs mention that the dictionary should not change, not sure what it means but would locals() be applicable in lab-reports where data won't change, for example in measurements?

Kamerad answered 14/2, 2011 at 20:58 Comment(1)
It is clear from the answers that it is not obvious at all why this is a bad idea but there seems to be 2 likely reasons. 1) You might not be modifying the scope you intend to modify and 2) The variable you are trying to modify might not actually get modified. See answers below for further details.Plow
A
0

Modification is a bad idea because the documentation (which you link) explicitly says not to:

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.

You don't need any more reason than that.

If you are using it in a way that doesn't modify any variables, then you'll be fine, but I'd question the design and see if there's a better way to do what you want.


In the specific example you link, locals is actually globals(), as you use it in the global scope of a module. This very specific use works now and, though I expect it to continue to work just as with globals, you might as well just use globals instead.

An even cleaner solution is probably, without knowing the rest of your design, to use a regular ol' dictionary for your variables; then use data["x"] = value instead of globals()["x"] = value.

Ayakoayala answered 14/2, 2011 at 21:12 Comment(3)
When someone asks "why do the docs say that this is a bad idea", responding by saying "because the docs say so" is not a useful or informative answer.Submit
@GlennMaynard: He does not say "why do the docs say", he asks "why is it a bad idea". Since he is not in a position to change the behavior and the docs, the warning from the docs is plenty of justification to not modify values – especially when there are two easy workarounds (both mentioned above).Ayakoayala
@FredNurk Your answer doesn't explain "why is it a bad idea". It basically just says "the docs say it is a bad idea, so don't question why"... Bad answer.Plow
C
11

What documentation says is that when you have a local x variable and do locals()['x'] = 42, then x may still point to the old object.

def foo():
    x = 0xABCD
    locals()['x'] = 42
    print(x)

foo()
Christianachristiane answered 14/2, 2011 at 21:2 Comment(6)
Is there a reason why this is not possible? I am literally trying to do something like this in combination with exec/eval but it is not possible. Why do Python 3.6 e.g. do not let me change the previous variable(s)?Lambdoid
@Lambdoid because you almost certainly don't have to do this. There's almost never a good use-case for dynamically altering the local namespace, and since allowing you to do so prevented an optimization in Python 3 (the local namespace is no longer a dict but an array for faster look-ups), then the language designers decided it wasn't important enough to let you do thatHowse
An extremely hacky and ugly workaround is described in How to convert this Python 2.7 code to Python 3?Cyano
@Howse People coming to this question because they have an use-case to do this: are you kidding me faceSomnambulism
@Somnambulism I doubt it is a valid oneHowse
@Howse You shouldn't ;) In Spark UDF, varargs concept is not supported which is understandable, so I cannot get the parameters in a list-like format. But I have to do null check and lower on all of the parameters. This is a really good use-case to be able to modify the parameters using one algorithm rather than having a long, duplicated if-else tree for like 10 parameters knowing that the function's signature will change in the future. Current workaround: put the parameters in tuple, transform them, then unpack. Explicit name listing is still required. It will broke I promise.Somnambulism
D
6

In certain cases, the call to locals() returns values collected from multiple sources, rather than a pointer to the local scope.

Example: When inside a function call, locals() returns a combination of the global scope and the scope local to the function. In this case, modifying the locals() output won't make any changes to the local scope because it's essentially using an island. It seems like the only cases where it does work are cases where its output is the same as the output of globals().

So, in other words, you either want to use globals(), or find a different way to achieve the same goal.

Divestiture answered 11/5, 2011 at 5:21 Comment(4)
What is an island?Amey
@AntonyHatchkins I have no idea what I meant by that. Hah!Divestiture
I'm guessing that "island" was meant to refer to something that is isolated from its surrounding. So the locals() dictionary holds copies rather than pointers to the original objects, which is why modifying locals() doesn't modify the original objects.Holo
So.... a scope?Plow
S
4

In the CPython interpreter, local variables can come from a number of places (the details of this are not important, but it has to do with how variables are stored for closures). The locals() function gathers up the names and values from all these places, to give you convenient access to them all in one place, but since it doesn't know where a given variable came from, it can't put it back. In other words, it's a bad idea because it doesn't work.

Systemize answered 14/2, 2011 at 21:39 Comment(0)
T
3

From Dive into Python

locals is a function that returns a dictionary, and here you are setting a value in that dictionary. You might think that this would change the value of the local variable x to 2, but it doesn't. locals does not actually return the local namespace, it returns a copy. So changing it does nothing to the value of the variables in the local namespace.

Tableware answered 14/2, 2011 at 21:2 Comment(1)
That is inaccurate: locals() doesn't always return a copy. However, the cases where modifying locals() actually has an effect are an implementation detail and not part of the language definition so you must not depend on that behaviour.Parasitize
A
0

Modification is a bad idea because the documentation (which you link) explicitly says not to:

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.

You don't need any more reason than that.

If you are using it in a way that doesn't modify any variables, then you'll be fine, but I'd question the design and see if there's a better way to do what you want.


In the specific example you link, locals is actually globals(), as you use it in the global scope of a module. This very specific use works now and, though I expect it to continue to work just as with globals, you might as well just use globals instead.

An even cleaner solution is probably, without knowing the rest of your design, to use a regular ol' dictionary for your variables; then use data["x"] = value instead of globals()["x"] = value.

Ayakoayala answered 14/2, 2011 at 21:12 Comment(3)
When someone asks "why do the docs say that this is a bad idea", responding by saying "because the docs say so" is not a useful or informative answer.Submit
@GlennMaynard: He does not say "why do the docs say", he asks "why is it a bad idea". Since he is not in a position to change the behavior and the docs, the warning from the docs is plenty of justification to not modify values – especially when there are two easy workarounds (both mentioned above).Ayakoayala
@FredNurk Your answer doesn't explain "why is it a bad idea". It basically just says "the docs say it is a bad idea, so don't question why"... Bad answer.Plow

© 2022 - 2024 — McMap. All rights reserved.