10

For example, in the code below I would like to obtain the list [1,2,3] using x as a reference.

In[1]: pasta=[1,2,3]
In:[2]: pasta
Out[2]: [1, 2, 3]
In [3]: x='pas'+'ta'
In [4]: x
Out[4]: 'pasta'
Roman Bodnarchuk
  • 29,461
  • 12
  • 59
  • 75
Luis Damiani
  • 103
  • 5
  • 11
    [Keep data out of your variable names.](http://nedbatchelder.com/blog/201112/keep_data_out_of_your_variable_names.html) – Sven Marnach Feb 22 '12 at 14:31
  • Everyone has posted good hacks to get what you want. But everyone has warned you that it's not good practice to do what you're trying to do. So why are you trying to do this? There may be (ahem, likely is) a better way... – inspectorG4dget Feb 22 '12 at 15:08
  • Thanks, everybody ... SO is really awesome! I have being using SO info of years, always from a Google search. This time, really couldn't find an answer for this question although it looked basic, so decided to post my first Q. Seconds latter I had already some high quality answers. Thanks! – Luis Damiani Feb 22 '12 at 18:18

4 Answers4

13

What you are trying to do is a bad practice.

What you really need is a dict:

>>> dct = {'pasta': [1,2,3]}
>>> x = 'pas' + 'ta'
>>> dct[x]
[1, 2, 3]

This is the right data structure for the actual task you're trying to achieve: using a string to access an object.

Other answers suggested (or just showed with a worning) different ways to do that. Since Python is a very flexible language, you can almost always found such different ways to follow for a given task, but "there should be one-- and preferably only one --obvious way to do it"[1].

All of them will do the work, but not without downsides:

  • locals() is less readable, needlessly complex and also open to risks in some cases (see Mark Byers answer). If you use locals() you are going to mix the real variables with the database ones, it's messy.
  • eval() is plain ugly, is a "quick-and-dirty way to get some source code dynamically"[2] and a bad practice.

When in doubt about the right way to choose, tring to follow the Zen of Python might be a start.

And hey, even the InteractiveInterpreter could be used to access an object using a string, but that doesn't mean I'm going to.

Community
  • 1
  • 1
Rik Poggi
  • 28,332
  • 6
  • 65
  • 82
2

Well, to do what you literally asked for, you could use locals:

>>> locals()[x]
[1, 2, 3]

However it is almost always a bad idea to do this. As Sven Marnach pointed out in the comments: Keep data out of your variable names. Using variables as data could also be a security risk. For example, if the name of the variable comes from the user they might be able to read or modify variables that you never intended them to have access to. They just need to guess the variable name.

It would be much better to use a dictionary instead.

>>> your_dict = {}
>>> your_dict['pasta'] = [1, 2, 3]
>>> x = 'pas' + 'ta'
>>> your_dict[x]
[1, 2, 3]
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
2

Like other pointed out, you should normally avoid doing this and just use either a dictionary (in an example like you give) or in some cases a list (for example instead of using my_var1, my_var2, my_var3 -> my_vars).

However if you still want to do that you have a couple of option.

Your could do:

locals()[x]

or

eval(x) #always make sure you do proper validation before using eval. A very powerfull feature of python imo but very risky if used without care.

If the pasta is an object attribute you can get it safely by:

getattr(your_obj, x)
Bogdan
  • 8,017
  • 6
  • 48
  • 64
  • That's it! Most complete answer! Thanks! – Luis Damiani Feb 22 '12 at 14:40
  • 2
    @LuisDamiani, this is really bad practice. It's hacky and not straight forward. A dict is exactly what you're looking for and should be used instead. – Jeff LaFay Feb 22 '12 at 14:45
  • 1
    Yeah. And if `x` doesn't contain `'hello'`, but `'import os;os.system("rm -rf /")'`, it executes as well, even if not intended... – glglgl Feb 22 '12 at 14:46
  • 1
    Why the downvotes? This does answer the question, doesn't it. – georg Feb 22 '12 at 15:38
  • 1
    @thg435: I downvoted for the lack of warnings. To simply throw a solution without warning an unexperienced user that a solutions is just a hack to better avoid (`locals()`) or that it might have risks (`eval`), it's not a good answer IMO. Bogdan is free to use the good comments left by others to improve his answer, and I will remove my downvote. – Rik Poggi Feb 22 '12 at 15:56
  • @RikPoggi, from what I can see, this is the OP's first post on SO. I don't know what makes you think he's "unexperienced" and needs to be lectured about "best practices". – georg Feb 22 '12 at 16:01
  • @thg435: I really don't want to start a discussion (here is not the place), and I have already expressed my thoughts and opinion about the downvote. Anyway the point of SO is that *"Answers are the real unit of work in any Q&A system."* - [Optimizing For Pearls, Not Sand](http://blog.stackoverflow.com/2011/06/optimizing-for-pearls-not-sand/). We are not just here to solve the OP problem but to provide good references for whoever comes later with the same question. So the OP might or might-not be a skilled pythonist, but it really doesn't matter. The answers are for everyone, for the community. – Rik Poggi Feb 22 '12 at 16:30
  • Not a very good warning, but I'm going to remove the down-vote. – Rik Poggi Feb 24 '12 at 12:46
0

Use this

hello = [1,2,3]
print vars()['hello']

Returns [1, 2, 3].

MMM
  • 7,221
  • 2
  • 24
  • 42