Dynamic local variable

How do you dynamically set a local variable in Python?

(where the variable name is dynamic)

UPDATE: I know this is not a good practice, and the comments are legitimate, but that does not make it a bad question, but more theoretical - I do not why it justifies downvotes.

+71
python dynamic
Nov 06 '11 at 17:03
source share
7 answers

Unlike other answers already posted, you cannot directly modify locals() and expect it to work.

 >>> def foo(): lcl = locals() lcl['xyz'] = 42 print(xyz) >>> foo() Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> foo() File "<pyshell#5>", line 4, in foo print(xyz) NameError: global name 'xyz' is not defined 

Modification of locals() is undefined. Outside the function, when locals() and globals() are the same, it will work; function inside usually doesn't work.

Use a dictionary or set an attribute for an object:

 d = {} d['xyz'] = 42 print(d['xyz']) 

or if you want, use the class:

 class C: pass obj = C() setattr(obj, 'xyz', 42) print(obj.xyz) 

Edit : Access to variables in namespaces that are not functions (so modules, class definitions, instances) are usually performed by dictionary lookups (as Sven points out in the comments, there are exceptions, for example classes that define __slots__ ). Local function locators can be optimized for speed, because the compiler (usually) knows all the names in advance, so the dictionary does not exist until you call locals() .

In the C Python implementation, locals() (called from within the function) creates a regular dictionary initialized from the current values ​​of local variables. In each function, any number of locals() calls will return the same dictionary, but each locals() call will update it with the current values ​​of local variables. This may give the impression that assignment to dictionary elements is ignored (I originally wrote that it was). Changes to existing keys in the dictionary returned with locals() , therefore, continue only until the next call to locals() in the same scope.

In IronPython, everything works differently. Any function that calls locals() inside it uses the dictionary for its local variables, so assignments to local variables change the dictionary and assignments to the dictionary change BUT variables, which is only if you explicitly call locals() in that name. If you associate another name with the locals function in IronPython, then calling it gives local variables for the area where the name was associated, and there is no way to access local functions through it:

 >>> def foo(): ... abc = 123 ... lcl = zzz() ... lcl['abc'] = 456 ... deF = 789 ... print(abc) ... print(zzz()) ... print(lcl) ... >>> zzz =locals >>> foo() 123 {'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456} {'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456} >>> 

All of this can change at any time. The only thing guaranteed is that you cannot depend on the results of assigning the dictionary returned by locals() .

+60
Nov 06 '11 at 17:11
source share

Others suggested assigning locals() . This will not work inside a function where access to local networks is done using the LOAD_FAST , unless you have an exec statement somewhere in the function. To support this statement, which could create new variables that are unknown at compile time, Python then accesses the local variables by name inside the function, so writing to locals() works. exec may be outside the code of the code that is being executed.

 def func(varname): locals()[varname] = 42 return answer # only works if we passed in "answer" for varname exec "" # never executed func("answer") >>> 42 

Note. This only works in Python 2.x. They ended this stupidity in Python 3, and other implementations (Jython, IronPython, etc.) may also not support it.

It is a bad idea. How do you access variables if you don't know their name? Probably locals()[xxx] . So why not just use your own dictionary and not pollute locals() (and perhaps rewrite the variable that your function really needs)?

+21
Nov 06 '11 at 17:12
source share

I spent the last ... a couple of hours, I think, trying to crack the lack of function closure, and I came up with this that could help:

 common_data = ...stuff... def process(record): ...logic... def op(): for fing in op.func_dict: # Key line number 1 exec(fing + " = op.func_dict[fing]") # Key line number 2 while common_data.still_recieving: with common_data._lock: if common_data.record_available: process(common_data.oldest_record) time.sleep(1.0) op.func_dict.update(locals()) # Key line number 3 threading.Thread(target = op).start() ... 

This is a rather difficult / far-fetched example, but if there are a lot of local residents, or you are still in the process of prototyping, this template becomes useful. Basically, I was just bitter about the fact that all data stores are replicated or moved to handle callback delegates, etc.

+3
Oct 13 '12 at 3:19
source share

You can directly change locals() :

 locals()['foo'] = 'bar' 

But the best way would be to have some kind of voice recorder that contains all your dynamic variable names as dictionary keys:

 d = {} for some in thing: d[some] = 'whatever' 
+1
Nov 06 2018-11-11T00:
source share

You can use the local dictionary and put all dynamic bindings as elements in the dictionary. Then, knowing the name of such a "dynamic variable", you can use this name as a key to get its value.

+1
Nov 06 2018-11-11T00:
source share

(Just a quick note for other googlin)

Ok, so changing locals() is not the way to go (when changing globals() should work ). In the meantime, exec may be, but it is very slow, therefore, as in the case of regular expressions, we can first compile() :

 # var0 = 0; var1 = 1; var2 = 2 code_text = '\n'.join( "var%d = %d" % (n, n) for n in xrange(3) ) filename = '' code_chunk = compile( code_text, filename, 'exec' ) # now later we can use exec: exec code_chunk # executes in the current context 
+1
18 Sep '13 at 10:29
source share

Say we have a dictionary below:

 DictionaryA = {'No Rating': ['Hobbit', 'Movie C', 'Movie G'], 'Forget It': ['Avenger', 'Movie B'], 'Must See': ['Children of Men', 'Skyfall', 'Movie F'], '3': ['X-Men', 'Movie D'], '2': ['Captain America', 'Movie E'], '4': ['Transformers', 'Movie A']} 

I want to create new dictionaries as shown below:

 NewDictionary1 = {'No Rating': ['Hobbit', 'Movie C', 'Movie G']} NewDictionary2 = {'Forget It': ['Avenger', 'Movie B']} NewDictionary3 = {'Must See': ['Children of Men', 'Skyfall', 'Movie F']} 

a oneliner:

 dics = [{k:v} for k,v in DictionaryA.iteritems()] 

will be displayed on:

 [{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}, {'Forget It': ['Avenger', 'Movie B']}, {'No Rating': ['Hobbit', 'Movie C', 'Movie G']}, {'3': ['X-Men', 'Movie D']}, {'2': ['Captain America', 'Movie E']}, {'4': ['Transformers', 'Movie A']}] 

But for the exact declaration of variables, we could:

 >>> i=0 >>> lcl = locals() >>> for key,val in DictionaryA.iteritems(): lcl["Dict" + str(i)] = {key:val} i += 1 

As you can see the first 3 Dict variables:

 >>> Dict0 {'Must See': ['Children of Men', 'Skyfall', 'Movie F']} >>> Dict1 {'Forget It': ['Avenger', 'Movie B']} >>> Dict2 {'No Rating': ['Hobbit', 'Movie C', 'Movie G']} 

As others have mentioned, if you want to put it in a function, you have to add it to globals() :

 >>> glb = globals() >>> for key,val in DictionaryA.iteritems(): glb["Dict" + str(i)] = {key:val} i += 1 
0
Jun 07 '14 at 13:13
source share



All Articles