在分析器中报告非致命错误的Pythonic方法是什么? [英] What's the Pythonic way to report nonfatal errors in a parser?

查看:105
本文介绍了在分析器中报告非致命错误的Pythonic方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建的解析器从文件读取记录的象棋游戏。 API使用如下:

  import chess.pgn 

pgn_file = open(games.pgn)

first_game = chess.pgn.read_game(pgn_file)
second_game = chess.pgn.read_game(pgn_file)
#...

有时会遇到非法移动(或其他问题)。什么是好的Pythonic方法来处理它们?




  • 一旦出现错误,就提高异常。然而,这使得每个问题都致命,因为执行停止。通常,仍然有一些已被解析并可以返回的有用数据。此外,您不能简单地继续解析下一个数据集,因为我们仍然处于半读数据的中间。


  • 累积异常并提高它们在游戏结束时。这使得错误再次致命,但至少你可以抓住它并继续解析下一个游戏。


  • 引入一个可选参数,如下所示:

      game = chess.pgn.read_game(pgn_file,parser_info)
    如果parser_info.error:
    #这看起来很冗长。
    #现在,您至少可以充分利用成功解析的部分。
    #...




一些这些或其他方法在野外使用

解决方案

实际上,这些致命错误 - - 至少能够再现正确的游戏;另一方面,也许玩家实际上做了非法的行动,当时没有人注意到(这会引起警告,而不是致命的错误)。



致命错误(文件已损坏)和警告(非法移动)的可能性,但随后的移动显示与该移动一致(换句话说,用户错误,当时没有人抓住它))我推荐使用第一个和第二个选项:




  • 继续解析不可选时引发异常

  • 收集任何错误/警告,不排除进一步解析直到结束



如果您没有遇到致命错误,那么您可以返回游戏加上任何警告/非致命错误,最后:

 返回游戏,警告,错误

但是如果您遇到致命错误怎么办?



没问题:创建可以附加可用的自定义异常游戏的一部分和任何其他警告/非致命错误:

  raise ParsingError(
'error explanation here ',
game = game,
warnings = warnings,
errors = errors,

然后当您捕获错误时,您可以访问游戏的可恢复部分,以及警告和错误。



自定义错误可能是:

 类ParsingError(异常):
def __init __(自我,msg,游戏,警告,错误)
super().__ init __(msg)
self.game = game
self.warnings = warnings
self.errors = errors

并在使用中:

  
first_game,warnings,errors = chess.pgn.read_game(pgn_file)
除了chess.pgn.ParsingError为err:
first_game = err.game
warnings = err.warnings
errors = err.errors
#无论你还有什么t来处理异常

这类似于 subprocess 模块处理错误。



为了在游戏致命错误后检索和解析后续游戏的能力,我建议您更改API: p>


  • 有一个游戏迭代器,只需返回每个游戏的原始数据(它只需要知道如何知道一个游戏结束,下一个开始)

  • 让解析器使用原始游戏数据并进行解析(因此,您不再需要在文件中遇到的位置)



    • 这样,如果你有一个五游戏文件和游戏两个死,你仍然可以尝试解析游戏3,4和5。


      A parser I created reads recorded chess games from a file. The API is used like this:

      import chess.pgn
      
      pgn_file = open("games.pgn")
      
      first_game = chess.pgn.read_game(pgn_file)
      second_game = chess.pgn.read_game(pgn_file)
      # ...
      

      Sometimes illegal moves (or other problems) are encountered. What is a good Pythonic way to handle them?

      • Raising exceptions as soon as the error is encountered. However, this makes every problem fatal, in that execution stops. Often, there is still useful data that has been parsed and could be returned. Also, you can not simply continue parsing the next data set, because we are still in the middle of some half-read data.

      • Accumulating exceptions and raising them at the end of the game. This makes the error fatal again, but at least you can catch it and continue parsing the next game.

      • Introduce an optional argument like this:

        game = chess.pgn.read_game(pgn_file, parser_info)
        if parser_info.error:
           # This appears to be quite verbose.
           # Now you can at least make the best of the sucessfully parsed parts.
           # ...
        

      Are some of these or other methods used in the wild?

      解决方案

      Actually, those are fatal errors -- at least, as far as being able to reproduce a correct game; on the other hand, maybe the player actually did make the illegal move and nobody noticed at the time (which would make it a warning, not a fatal error).

      Given the possibility of both fatal errors (file is corrupted) and warnings (an illegal move was made, but subsequent moves show consistency with that move (in other words, user error and nobody caught it at the time)) I recommend a combination of the first and second options:

      • raise an exception when continued parsing isn't an option
      • collect any errors/warnings that don't preclude further parsing until the end

      If you don't encounter a fatal error then you can return the game, plus any warnings/non-fatal errors, at the end:

      return game, warnings, errors
      

      But what if you do hit a fatal error?

      No problem: create a custom exception to which you can attach the usable portion of the game and any other warnings/non-fatal errors to:

      raise ParsingError(
          'error explanation here',
          game=game,
          warnings=warnings,
          errors=errors,
          )
      

      then when you catch the error you can access the recoverable portion of the game, along with the warnings and errors.

      The custom error might be:

      class ParsingError(Exception):
          def __init__(self, msg, game, warnings, errors):
              super().__init__(msg)
              self.game = game
              self.warnings = warnings
              self.errors = errors
      

      and in use:

      try:
          first_game, warnings, errors = chess.pgn.read_game(pgn_file)
      except chess.pgn.ParsingError as err:
          first_game = err.game
          warnings = err.warnings
          errors = err.errors
          # whatever else you want to do to handle the exception
      

      This is similar to how the subprocess module handles errors.

      For the ability to retrieve and parse subsequent games after a game fatal error I would suggest a change in your API:

      • have a game iterator that simply returns the raw data for each game (it only has to know how to tell when one game ends and the next begins)
      • have the parser take that raw game data and parse it (so it's no longer in charge of where in the file you happen to be)

      This way if you have a five-game file and game two dies, you can still attempt to parse games 3, 4, and 5.

      这篇关于在分析器中报告非致命错误的Pythonic方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆