Reputation: 10995
My Input is:
input = ['(var1, )', '(var2,var3)']
Expected Output is:
output = [('var1', ), ('var2','var3')]
Iterating over input and using eval
/literal_eval
on the tuple-strings is not possible:
>>> eval('(var1, )')
>>> NameError: name 'var1' is not defined
How can I convert an item such as '(var1, )'
to a tuple where the inner objects are treated as strings instead of variables?
Is there a simpler way than writing a parser or using regex?
Upvotes: 7
Views: 750
Reputation: 24699
Try this:
tuples = [tuple(filter(None, t.strip('()').strip().split(','))) for t in input]
For example:
In [16]: tuples = [tuple(filter(None, t.strip('()').strip().split(','))) for t in input]
In [17]: tuples
Out[17]: [('var1',), ('var2', 'var3')]
We're iterating through our list of tuple strings, and for each one, removing the ()
s, then splitting our string into a list by the ,
, and then converting our list back into a tuple. We use filter()
to remove empty elements.
Upvotes: 5
Reputation: 46533
For each occurrence of a variable, eval
searches the symbol table for the name of the variable. It's possible to provide a custom mapping that will return the key name for every missing key:
class FakeNamespace(dict):
def __missing__(self, key):
return key
Example:
In [38]: eval('(var1,)', FakeNamespace())
Out[38]: ('var1',)
In [39]: eval('(var2, var3)', FakeNamespace())
Out[39]: ('var2', 'var3')
Note: eval
copies current globals to the submitted globals
dictionary, if it doesn't have __builtins__
. That means that the expression will have access to built-in functions, exceptions and constants, as well as variables in your namespace. You can try to solve this by passing FakeNamespace(__builtins__=<None or some other value>)
instead of just FakeNamespace()
, but it won't make eval
100% safe (Python eval: is it still dangerous if I disable builtins and attribute access?)
Upvotes: 12
Reputation: 78700
I like vaultah's solution. Here's another one with ast.literal_eval
and re
if eval
is not an option:
>>> import re
>>> from ast import literal_eval
>>> [literal_eval(re.sub('(?<=\(|,)(\w+)(?=\)|,)', r'"\1"', x)) for x in input]
[('var1',), ('var2', 'var3')]
Upvotes: 4