Python调用int()时优雅失败?

1 投票
4 回答
785 浏览
提问于 2025-04-15 15:13

我需要在一个类里做一个简单的有限状态机(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 个回答

1

你得到了很好的答案,和你的问题很匹配。不过,有时候确实会有一些情况,你可能想把某些字段转换成 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 模式;但在更一般的情况下,如果你没有这么精确的信息,这种做法可能就合适了!

4

这个方法很实用,但我不确定它是否符合“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 的时候,可以省略参数,因为默认设置在这里就能正常工作。

编辑:重新格式化了一下 - 在实际代码中,我不会把它写成一行。

12

你其实只需要解析那些你认为是整数的部分。

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]))

撰写回答