Python调用int()时优雅失败?
我需要在一个类里做一个简单的有限状态机(FSM),并且用Python来写。这个作业要求我们从一个文本文件中读取机器的状态转换。所以,比如说,一个有3个状态的FSM,每个状态有2个可能的转换,输入可以是'a'和'b',那么这个文本文件可能长这样:
2 # first line lists all final states
0 a 1
0 b 2
1 a 0
1 b 2
2 a 0
2 b 1
我想找一种更符合Python风格的方法来逐行读取,并把状态转换成整数,同时保持输入值为字符串。基本上,我的想法是这样的:
self.finalStates = f.readline().strip("\n").split(" ")
for line in f:
current_state, input_val, next_state = [int(x) for x in line.strip("\n").split(" ")]
当然,当它尝试把字符串"a"转换成整数时,会抛出一个ValueError错误。我知道我可以用传统的循环来处理这个错误,但我希望能有一种更符合Python风格的方法来做到这一点。
4 个回答
你得到了很好的答案,和你的问题很匹配。不过,有时候确实会有一些情况,你可能想把某些字段转换成 int
类型(也就是整数),如果这些字段都是数字的话;而如果不是数字,就保持它们为 str
类型(字符串),就像你问题的标题所提到的那样。关键是你事先并不知道哪些字段是整数,哪些不是。
在传统的Python写法中,我们会用 try/except 这种方式来处理:
def maybeint(s):
try: return int(s)
except ValueError: return s
不过,你需要把它放到一个函数里,因为在表达式中(比如在列表推导式里)是不能直接使用 try/except 的。所以,你可以这样使用:
several_fields = [maybeint(x) for x in line.split()]
不过,如果你愿意的话,其实也可以在一行里完成这个特定的任务:
several_fields = [(int(x) if x.isdigit() else x) for x in line.split()]
这里的 if
/else
三元运算符看起来有点奇怪,但用久了就习惯了;而字符串的 isdigit
方法会在字符串不为空且只包含数字时返回 True。
再强调一下,这并不是说在你具体的情况下应该这样做,因为你已经知道输入类型的具体 int
-str
-int
模式;但在更一般的情况下,如果你没有这么精确的信息,这种做法可能就合适了!
这个方法很实用,但我不确定它是否符合“Python风格”……可能会让一些人感到困惑。如果你有很多值,实际上应该使用一个“懒惰”的 zip() 来处理。
types = [int, str, int]
for line in f:
current_state, input_val, next_state = multi_type(types, line)
def multi_type(ts,xs): return [t(x) for (t,x) in zip(ts, xs.strip().split())]
另外,你在使用 strip 和 split 的时候,可以省略参数,因为默认设置在这里就能正常工作。
编辑:重新格式化了一下 - 在实际代码中,我不会把它写成一行。
你其实只需要解析那些你认为是整数的部分。
for line in f:
tokens = line.split(" ")
current_state, input_val, next_state = int(tokens[0]), tokens[1], int(tokens[2])
这样写可能更容易理解:
for line in f:
current_state, input_val, next_state = parseline(line)
def parseline(line):
tokens = line.split(" ")
return (int(tokens[0]), tokens[1], int(tokens[2]))