【问题标题】:Python graceful fail on int() call?Python 在 int() 调用上优雅失败?
【发布时间】:2009-10-20 20:30:26
【问题描述】:

我必须在课堂上制作一个基本的 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

我正在尝试提出一种更 Pythonic 的方式来一次读取一行并将状态转换为整数,同时将输入 vals 保留为字符串。基本上是这样的:

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

当然,当它尝试 int("a") 时,它会抛出一个 ValueError。我知道我可以使用传统循环并捕获 ValueError,但我希望有一种更 Pythonic 的方式来执行此操作。

【问题讨论】:

  • “Pythonnic 方式”是什么意思?编写大而难以阅读的代码行?

标签: python fsm


【解决方案1】:

您实际上应该只尝试解析您期望为整数的标记

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

【讨论】:

    【解决方案2】:

    这是一个非常实用的东西,但我不确定它是否是“pythonic”......而且它可能会让一些人摸不着头脑。如果你有大量的值,你真的应该有一个“懒惰的” 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 的参数也可以省略,因为这里可以使用默认值。

    编辑:重新格式化 - 我不会将它用作实际代码中的一长行。

    【讨论】:

    • 如果我的行仅包含三个值,但如果它们包含更多值,我认为我不会采用这种方法?绝对。
    • 如果您需要经常更改单个参数的“类型”函数,这也是一个非常好的解决方案 - 即将参数 1 从 int() 切换到 str()
    【解决方案3】:

    您得到了与您的问题完美匹配的出色答案。但是,在其他情况下,可能确实存在您希望将某些字段转换为 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】:
      self.finalStates = [int(state) for state in f.readline().split()]
      
      for line in f:
          words = line.split()
          current_state, input_val, next_state = int(words[0]), words[1], int(words[2])
          # now do something with values
      

      请注意,您可以将 line.strip("\n").split(" ") 缩短为 line.split()str.split() 的默认行为是在任何空白处进行拆分,它将返回一组没有任何前导或尾随空白的单词。

      如果您在循环中将状态转换为 int,我认为您希望 finalStates 也为 int

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-07
        • 2018-02-02
        • 1970-01-01
        • 2021-11-15
        • 2015-09-25
        • 2017-01-03
        • 1970-01-01
        相关资源
        最近更新 更多