-1

I am trying to improve my existing code, is there any way to affect multiples different variables without using dict or lists or tuples?? I am trying to write something like:

number1 = 1
number2 = 2
number3 = 3

for i in (1,2,3):
    number{i} += 1

and then have number1 = 2 number2 = 3 and number3 = 4

i was thinking about formatting string but it doesn't work, thx for reading.

  • because this is a simple example with numbers. i am actually doing things with objects of a class i created, theses objects are getting values from sql selects statements, and i affect 1 object for each row –  Oct 28 '12 at 17:22
  • huh? just iterate over the rows to affect 1 object for each row - if you can use an index, use lists, if you can use a fetched value from the data, use a dictionary – Aprillion Oct 28 '12 at 17:27
  • 1
    By avoiding dicts, lists, and tuples, you're making your code *worse*, not better. – DSM Oct 28 '12 at 17:53

2 Answers2

3

A better approach here would be to use dictionary :

In [26]: numbers={'number1': 1,
   ....:          'number2' : 2,
   ....:           'number3' : 3}

In [27]: for i in (1,2,3):
   ....:         numbers['number'+str(i)]+=1
   ....: 

In [28]: numbers['number1']
Out[28]: 2

In [29]: numbers['number2']
Out[29]: 3

In [30]: numbers['number3']
Out[30]: 4

otherwise you can also you globals():

In [31]: number1 = 1

In [32]: number2 = 2

In [33]: number3 = 3

In [34]: for i in (1,2,3):
   ....:     globals()['number'+str(i)]+=1
   ....:     
   ....:     

In [35]: number1
Out[35]: 2

In [36]: number2
Out[36]: 3

In [37]: number3
Out[37]: 4
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
3

You can access variables via a string representation of their name by using the dictionaries returned either globals() or locals() as appropriate - although you may find things don't behave as you expect if you modify the locals() dictionary, as noted in the docs and demonstrated by a code snippet at the bottom of this answer. You can also modify instance, class, or module variables via string labels by using, respectively, setattr(self, 'some_variable_name', value), setattr(ClassName, 'some_variable_name', value) or setattr(ModuleName, 'some_variable_name', value) where self, ClassName and ModuleName are respectively references to a class instance, a class, and a module. Finally, you could always achieve what you want by using exec to execute code contained in strings. For example:

for i in range(5):
    temp = i
    exec('var%d = temp' % i)
print var0, var1, var2, var3, var4

will print 0 1 2 3 4.

But why on earth would you want to do any of these things? You can just create and use a dictionary instead if you need to map arbitrary strings to values. If, as in your example, you're not dealing with arbitrary strings but rather with a sequence of variables that differ only by an integer index at the end of their name, then use a list because that's what lists are for.

Doing things in any of the ways I described in my first paragraph is confusing and pointless and I've never seen it done in real code.

I want to re-emphasize that the important thing here, as Ashwini Chaudhary has already pointed out, is that there is no reason to refer to variables via strings in this way because if you need to map strings to values, you can simply use a dictionary - which is exactly what you're indirectly doing anyway if you use globals() or locals(), since those functions each return dictionaries.


Anyway, as a postscript, I mentioned that things don't quite work right if you modify the locals() dictionary, which is not meant to be modified as noted in the docs, which remark

  • 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.

Well, here is an illustration of that point, and may it deter anyone from trying this approach:

var1 = 'asdf'
def test1():
    var1 = 'ghjkl'
    print globals()['var2']
    print locals()['var2']

test1()

def test2():
    globals()['var2'] = 'qwerty'
    locals()['var2'] = 'uiop'
    print var2

test2()

What gets printed if you run the above code? To my surprise, it's:

asdf
ghjkl
qwerty

The first test behaves as I'd expect - the lookup in globals finds the value assigned outside the function, and the lookup in locals finds the value assigned locally. The second test is the surprising one - even though we've assigned a value in globals and a value in locals, locally referring to the variable by name finds the value we place in the globals dictionary, not the locals one.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
  • 1
    The `locals()` fact you discovered is the reason that the docs say not to edit `locals()`. – DSM Oct 28 '12 at 17:52
  • @DSM Thanks, I missed that line in the docs when I skimmed them. I've updated my answer to reflect your observation. – Mark Amery Oct 28 '12 at 18:10