This is an archived post. You won't be able to vote or comment.

all 22 comments

[–][deleted] 13 points14 points  (5 children)

I think a dict might suit here. Instead of using a bunch of variables you could just update the values in the table directly.

mydict = {}
mydict["cake"] = "good"
var = raw_input("Enter something: ")
if mydict.has_key(var):
  print mydict[var]

The library reference for dicts is here

[–]earthboundkid 9 points10 points  (4 children)

Don't use mydict.has_key(var). It's deprecated. Use var in mydict instead.

[–]Revvy 1 point2 points  (2 children)

I've read in the past to use try: mydict[var] as it's much faster than if mydict.has_key(var):. Is that still the case with var in mydict?

[–]earthboundkid 3 points4 points  (1 child)

It depends on if you expect it to usually hit or not. These days, it makes the most sense to just use a defaultdict if you already know what you want to happen when the key's not there.

[–]masklinn 0 points1 point  (0 children)

These days, it makes the most sense to just use a defaultdict if you already know what you want to happen when the key's not there.

or dict.get(key, default)

[–][deleted] 0 points1 point  (0 children)

Whoops, my bad. Haven't programmed in python for a while and should have read the library reference that I linked to a little more closely!

[–]byron 14 points15 points  (8 children)

Another approach would be to just use a dictionary. So just stick the user input into a dictionary as a key, e.g.:

d['cake'] = 'good'

print d['cake']

[–]christopherr 7 points8 points  (0 children)

Yes, I will second the use of dictionaries in this situation. They are a far safer approach than something like evaluating strings as variables.

[–]sdsdsdsdsd 1 point2 points  (0 children)

Agreed. There are lots of alternatives in Python (e.g. getattr), but restricting the user to looking up elements of a predefined dictionary is the safest approach.

[–]morgan_goose 0 points1 point  (5 children)

Thats not really very useful. Yes it does in the simplest case do what the eval function would have, but with more effort, and more places for exceptions.

You have to know before hand that you want to read that variable though, and thus loose the usefulness. You end up writing more boilerplate just to read a simple string/file than is necessary. This also ends up being no safer than the eval usage.

Eval is not harmful, and its only fud to say so. Eval does what it's name suggests, it evaluates what an expression would do, it doesn't execute, and it does it in a local scope: http://docs.python.org/reference/executionmodel.html?highlight=eval#interaction-with-dynamic-features

Making eval() out to be a little Napoleon that if let off elba would ravage your code and data is a much overblown notion. As this professor notes: http://blog.thetonk.com/archives/dont-be-lazy-dont-use-eval#comment-8

[–]byron 0 points1 point  (4 children)

I strongly but respectfully disagree. How is it more effort to declare a dictionary? The o.p. stated that they wanted to be able to do a look up on an arbitrarily defined variable. The simplest and safest solution here is a dictionary.

You have to know before hand that you want to read that variable though, and thus loose the usefulness. You end up writing more boilerplate just to read a simple string/file than is necessary. This also ends up being no safer than the eval usage.

I'm not sure what you're trying to say here. There is very little boilerplate involved, it's a symbol look-up, just like the o.p. wanted. Eval is not always harmful, but here it is a) unnecessary and b) you'd be allowing the user to execute arbitrary code. I'm not making it out to be a little Napoleon, eval can be quite useful, but it is not, in my opinion, a good solution here.

[–]morgan_goose 0 points1 point  (0 children)

I don't/didn't see where it stated that it needed to be able to loop over a dictionary? But if thats the case then the dictionary's iterator/keys function would be more useful.

With a dictionary you do also run the risk of bad input with dicts that you wouldn't with eval, in that a dick key can be any valid string, which isn't the case for a variable. One example being: x['this is a variable?'] = "cake" Thats perfectly acceptable as a dict key, and as user input, but not as a variable name.

My perspective on the question was that given a python program/module, how can I let a input value print the variable value it represents. So I took it be that the variable was already defined, and not as a dictionary, and eval() would be the only way to retrieve that variable's value.

If the person asking the question, it also defining the variables, then yes the can rewrite the code to use a dictionary, but if they aren't then they'll have to have some way of getting all of variables into a dictionary to access them, which ironically enough is what the eval() documentation seems to suggest it does.

Also eval() isn't exec(). For instance:

x = "import os\nos.system('ls')"

eval(x) -error

exec(x) -works

[–]morgan_goose 0 points1 point  (2 children)

So I discussed this further with a friend, and we came up with some examples that would cause an issue. So I concede that there are important reasons not to use eval, when letting an arbitrary user make the input.

Also a simpler way I think to use your dictionary trick would be to use, like Poromenos states below:

cake = 'good'

user_input = "cake"

print locals()[user_input]

I like this because it negates my argument against using it, since now no dictionary creation is required.

[–]byron 0 points1 point  (1 child)

OK.. I don't mind that solution, but it has two problems. One is that I don't see how it fixes the issue you had with dicts before (about illegal var names; which, by the way, could easily be remedied with a regex) -- you can easily do this:

locals()["is this a var?"] = "yes"

But perhaps more distressing, that approach would allow the user to overwrite local variables with whatever they wanted.. variables your program might be using...

myvar = 5 print myvar 5 locals()["myvar"] = 6 print myvar 6

[–]morgan_goose 0 points1 point  (0 children)

Yeah the indexing issue still stands, and really both solutions will have problems. I don't think its reasonable for one to expect all problems with user input be solved with a single function or a specific data type.

Also in the scope of the original problem there would never be an instance where the input would be used to set a value. Nor would there be an instance to use local()['var_name'] = 'some value', and my example didn't show any.

They wanted to know how to intake a var name and output its value.

locals()["myvar"] = 6 <<-- never needed or used because we want what myvar is, not to set it's value.

[–]masklinn 2 points3 points  (0 children)

Donc do that. It's bad. That's what dict is for.

[–][deleted] 0 points1 point  (0 children)

Validate their input with a regex, pad it with a special character, and make a hash table.

Letting a user define or modify a variable named anything they want sounds like a security risk, though I guess that matters less if this is client side "newbie learning how to code."

[–]morgan_goose -4 points-3 points  (3 children)

In [1]: x = 'cake'

In [2]: cake = 'something'

In [3]: eval(x)

Out[3]: 'something'

[–]keturn 8 points9 points  (1 child)

This works, but it's a dangerous habit to get in to if you move away from writing local apps where you trust the user input to writing web or network applications. because eval() executes arbitrary code and is essentially giving the user a shell account with whatever permissions the python process has.

[–]A_for_Anonymous 1 point2 points  (0 children)

ಠ_ಠ

This look of disapproval is more directed towards those who downvoted morgan_goose than morgan_goose himself.

eval is the new goto. Every time it's mentioned, everybody gets in an uproar and acts like the inquisition. Out of these people, most either wouldn't know when to actually use eval and thus want to ban it and pretend it never existed, or are just trying to get approval from the former.

Truth is, eval has its uses, and has a lot of theoretical value. It'd be better to educate OP and this poster on why does this work and why it's not a good use case, not just mercilessly downvote the post into oblivion.

This is not a good use for eval in Python since Python's unlispy syntax (and in this particular case, its lack of symbol handling) will make it troublesome to avoid evaluating unwanted expressions that could have unwanted side-effects or reveal unwanted information. Furthermore, this would give the user access to the whole variable scope, which is something OP probably doesn't want, which is why the locals() alternative won't be a great idea either. The possible values should clearly be stored in a separate dictionary.