Reputation: 13
In my code I am reading lines from a file. Each line contains space delimited values.
foo True 8 9.2
bar False 17 -3.1
After reading the file and splitting the text by line. I will end up with a list.
lines = ['foo True 8 9.2', 'bar False 17 -3.1']
I then iterate through the lines and unpack the variables using .split()
:
for line in lines:
string, boolean, integer, floating_point = line.split()
I then cast each variable to its proper type:
boolean = bool(boolean)
integer = int(integer)
floating_point = float(floating_point)
My question is, is there a more Pythonic way to cast the variables and/or use less lines?
Upvotes: 1
Views: 533
Reputation: 123463
Here's another way to use ast.literal_eval()
:
import ast
def convert(s):
""" Determine value of (Python) literal given in string `s`. """
try:
return ast.literal_eval(s)
except ValueError:
return s
filename = 'data_file.txt'
with open(filename) as file:
for line in file:
string, boolean, integer, floating_point = (convert(item) for item in line.split())
print(string, boolean, integer, floating_point)
Output:
foo True 8 9.2
bar False 17 -3.1
Upvotes: 1
Reputation: 21453
when logic gets messy usually the solution is to abstract that logic to another function, and if the function represents an iterable then you would write a generator, for instance you could do this:
def mapTypes(values, types):
return (cast(v) for cast, v in zip(types, values))
def mapRows(file, rowTypes):
for line in file:
yield mapTypes(line.split(), rowTypes)
def str2bool(string):
if string == "True":
return True
elif string == "False":
return False
else:
raise ValueError("string must be True or False, got {!r}".format(string))
lines = ['foo True 8 9.2', 'bar False 17 -3.1']
for row in mapRows(lines, [str, str2bool, int,float]):
string, boolean, integer, floating_point = row
print(string, boolean, integer, floating_point)
Upvotes: 0
Reputation: 3503
Use ast.literal_eval
. Unlike eval
this only determines literals.
from ast import literal_eval
lines = ['foo True 8 9.2', 'bar False 17 -3.1']
for line in lines:
for word in line.split():
try:
eval_ed = literal_eval(word)
except ValueError:
eval_ed = word # it's a string, EAFP at it's finest
print(type(eval_ed), eval_ed)
Output:
<class 'str'> foo
<class 'bool'> True
<class 'int'> 8
<class 'float'> 9.2
<class 'str'> bar
<class 'bool'> False
<class 'int'> 17
<class 'float'> -3.1
Upvotes: 0