When I started to make my own scripts I learned that the eval() function could convert strings into lists, dictionaries, integers, floats, …
But soon enough I got some advice here and there not to use the eval() function like that, but to convert to a list using string.split(). This is good for converting lists, but with nested list it gets more complicated. So complicated I wonder if it wouldn’t be better just to use the eval() function. So my question, what should I do?
An example:
string = '1, 3, 5, 7, 11, 13, 17, 19'
array = [int(s) for s in string.replace(' ', '').split(',')]
So far so good, but now this:
string = '[1, 2, 3], 5, 'hello', [False, True], True'
array = eval(string) # permitted here to use eval() or not?
How is the string initially being created? Maybe you could bypass all of this by rethinking your logic. Oftentimes if you explain exactly what you are trying to accomplish someone on here will come up with an alternative way of doing it, rather than trying to force your current way of thinking into working.
So I guess my question is, why do you initially have a string of items and not generate them into a list when they are created?
You can use eval as long as you like if you find it useful, the only limit lies in the knowledge of the command itself.
In order, eval is not very safe (because it can eval “1+” or “i will kill your hard drive”), slowish and, generally speaking, makes the code a little harder to read because it’s a function whose outcome is entirely determined by its parameter, which is uncommon.
Given that, you decide if it’s worth it.
In the uni computer course we did, we got taught to never ever use eval. Mostly because it introduces security problems, but also because it is really hard to debug. It’s hard to tell what is being fed into it, and what the expected outcome is.
There isn’t a single occasion that I can think of when you’d need to use eval(). Allowing arbitrary code to run is incredibly dangerous and difficult to debug.
The string is a property on the game object that will be used to set parameters for position, speed, …
Is this a conventional way to do this or would some people say this module is also a bit arbitrary?
I think I’m asking a relevant question, if one may chose string properties as input. If eval() is not a (real) option, I still want to learn how to write my own function to convert such input.
What do you think about the ast module? Would you use this too? Or would you prefer to write your own function? (Given that it would be as complex as in the example).
@ pgi, sdfgeoff, agoose77: thanks for sharing your insight.
Then you can use it, unless performances are a problem. You could write your mini parser but it’s not worth the effort.
Security is not a problem, as soon as the BGE loads the first script security gets thrown out of the window.
If you have a property to set position, speed etc, then consider using float variables…
Seriously, have a property called ‘speed’ with a float value. No need for eval-ling anything.
If there are too many variables, then realize that no matter what you write, it is easiest to use blender’s ui to make/edit them.
The place that I used to think eval was useful is when you have a function, say ‘forwards’ and you have a dictionary that maps ‘WKEY’ to ‘forward.’ The easy thing to do is to eval the output of the dictionary search: eval(actions[‘WKEY’])
But it is better to make another dictionary that maps the two together.
No, I don’t think it would be better to have properties for every single parameter since then there would be about fifteen of them, and I would have to give them long names, such as: ‘move_start, move_stop, move_speed, …, scale_start, scale_stop, scale_speed, …’ So I believe it would be only logical to have string properties for ‘move’, ‘scale’ and ‘spin’.
After reading this through I think I won’t hesitate to use eval() for this particular case. It will only happen once at initialization, and it would probably run as fast as some function I would have to write to parse such data anyway.
Edit: But maybe using the ast module would be a better choice? If anyone has any thoughts on this?
Edit 2: I changed my mind and thought of trying to make a conversion script. I believe this will be much better than using eval() since it’s small and only serves a specific need.
def string_to_list(string):
def evaluate(s):
try:
return float(s)
except ValueError:
if s == 'False':
return False
elif s == 'True':
return True
else:
return s
nested_list = []
nested = False
for s in string[1:-1].replace(' ', '').split(','):
if not nested:
if '[' in s:
sub_list = [evaluate(s[1:])]
nested = True
else:
nested_list.append(evaluate(s))
elif ']' in s:
sub_list.append(evaluate(s[:-1]))
nested_list.append(sub_list)
nested = False
else:
sub_list.append(evaluate(s))
return nested_list
(the code snippets in your first post seams to be just samples. In a production environment, they would be nonsense.)
Btw. I use eval() in my save/loader to convert loaded strings into dictionaries. Using the save/LoadActuator or even pickle is more secure, but I wanted human readable text.
On it’s own it sounds like you need a different data type ;).
So you want the user to type in a comma separated list?
It seems you want to allow an own syntax for entering data. With that you need a parser anyway to transform the input into the required form for processing.