Быть питоническим с ошибками [дублировать]

8
задан cat 4 January 2016 в 01:17
поделиться

5 ответов

Фактически, эти являются фатальными ошибками - по крайней мере, поскольку они способны воспроизводить правильную игру; с другой стороны, возможно, игрок действительно совершил незаконный ход, и в то время никто не заметил (что сделало бы это предупреждение, а не фатальной ошибкой).

Учитывая возможность как фатальных ошибок (файл поврежден) и предупреждения (был сделан незаконный ход, но последующие шаги показывают согласованность с этим движением (другими словами, ошибка пользователя и никто не поймал его в то время)). Я рекомендую комбинацию первого и второго вариантов:

  • вызывает исключение, когда продолжение разбора не является опцией
  • для сбора любых ошибок / предупреждений, которые не препятствуют дальнейшему анализу до конца

] Если вы не сталкиваетесь с фатальной ошибкой, вы можете вернуть игру, а также любые предупреждения / нефатальные ошибки в конце:

return game, warnings, errors

Но что, если вы нажмете фатальную ошибку?

Нет проблем: создайте настраиваемое исключение, к которому вы можете прикрепить полезную часть игры и любые другие предупреждения / нефатальные ошибки:

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

, затем, когда вы поймаете ошибка, с которой вы можете получить доступ (/ g10)

Пользовательская ошибка может быть:

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

и используется:

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

Это похоже на то, как модуль subprocess обрабатывает ошибки.

Для возможности извлечения и анализа последующих игр после фатальной ошибки игры я предлагаю изменить ваш API:

  • имеют игровой итератор, который просто возвращает необработанные данные для каждой игры (он должен знать, как сказать, когда одна игра заканчивается, а следующая начинается)
  • имеют синтаксический анализатор, который принимает данные сырой игры и проанализируйте его (так что он больше не отвечает за то, где в файле вы оказались)

Таким образом, если у вас есть файл из пяти игр и две игры, вы все равно можете попытаться разыгрывают игры 3, 4 и 5.

6
ответ дан Ethan Furman 31 August 2018 в 17:46
поделиться

Я предложил щедрость, потому что я хотел бы знать, действительно ли это лучший способ сделать это. Тем не менее, я также пишу парсер, и поэтому мне нужна эта функциональность, и это то, что я придумал.


Модуль warnings именно то, что вы хотите.

Сначала меня отвратило то, что каждый пример предупреждения, используемого в документах, выглядит как этих :

Traceback (most recent call last):
  File "warnings_warn_raise.py", line 15, in <module>
    warnings.warn('This is a warning message')
UserWarning: This is a warning message

... что нежелательно, потому что я не хочу, чтобы он был UserWarning, мне нужно собственное собственное имя предупреждения.

Вот решение этого:

import warnings
class AmbiguousStatementWarning(Warning):
    pass

def x():
    warnings.warn("unable to parse statement syntax",
                  AmbiguousStatementWarning, stacklevel=3)
    print("after warning")

def x_caller():
    x()

x_caller()

, который дает:

$ python3 warntest.py 
warntest.py:12: AmbiguousStatementWarning: unable to parse statement syntax
  x_caller()
after warning
3
ответ дан cat 31 August 2018 в 17:46
поделиться

Без библиотек трудно сделать это чисто, но все же возможно.

В зависимости от ситуации существуют различные методы обработки.

Метод 1:

Поместить все содержимое цикла while в следующее:

while 1:
    try:
        #codecodecode
    except Exception as detail:
        print detail

Способ 2:

То же, что и метод 1, за исключением нескольких попыток / исключений, так что это не пропускает слишком много кода и amp; вы знаете точное местоположение ошибки.

Извините, в спешке, надеюсь, что это поможет!

0
ответ дан Douglas - 15 year old Pythoner 31 August 2018 в 17:46
поделиться

Самый Pythonic путь - это модуль logging . Это было упомянуто в комментариях, но, к сожалению, без особого упорства. Существует много причин, которые предпочтительнее предупреждений :

  1. Модуль предупреждений предназначен для сообщения предупреждений о возможных проблемах с кодом, а не плохих пользовательских данных.
  2. Первая причина на самом деле достаточно. : -)
  3. Модуль регистрации обеспечивает настраиваемую серьезность сообщения: не только предупреждения, но и сообщения от отладочных сообщений до критических ошибок.
  4. Вы можете полностью контролировать вывод модуля регистрации. Сообщения могут быть отфильтрованы по их источнику, содержимому и строгости, отформатированы любым способом, отправлены на разные выходные цели (консоль, трубы, файлы, память и т. Д.) ...
  5. Модуль регистрации отключает фактическую ошибку / предупреждение / сообщение и вывод сообщений: ваш код может генерировать сообщения соответствующего типа и не должен беспокоить, как они представлены конечному пользователю.
  6. Модуль регистрации является стандартом де-факто для кода Python. Все используют его везде. Поэтому, если ваш код использует его, объединение его с сторонним кодом (вероятно, с помощью ведения журнала) будет легким. Ну, может быть, что-то более сильное, чем ветер, но определенно не ураган категории 5. : -)

Основной пример использования для модуля протоколирования будет выглядеть следующим образом:

import logging
logger = logging.getLogger(__name__) # module-level logger

# (tons of code)
logger.warning('illegal move: %s in file %s', move, file_name)
# (more tons of code)

Это приведет к печати таких сообщений, как:

WARNING:chess_parser:illegal move: a2-b7 in file parties.pgn

(при условии, что ваш модуль называется chess_parser.py)

Самое главное, что вам не нужно ничего делать в вашем модуле парсера. Вы заявляете, что используете систему ведения журнала, вы используете логгер с определенным именем (то же самое, что и имя модуля анализатора в этом примере), и вы отправляете ему сообщения об уровне предупреждений. Ваш модуль не должен знать, как эти сообщения обрабатываются, отформатируются и сообщаются пользователю. Или, если они вообще сообщаются. Например, вы можете настроить модуль регистрации (обычно в самом начале вашей программы), чтобы использовать другой формат и выгрузить его в файл:

logging.basicConfig(filename = 'parser.log', format = '%(name)s [%(levelname)s] %(message)s')

И вдруг без каких-либо изменений кода вашего модуля, ваши предупреждающие сообщения сохраняются в файл с другим форматом, а не на печать:

chess_parser [WARNING] illegal move: a2-b7 in file parties.pgn

Или вы можете подавить предупреждения, если хотите:

logging.basicConfig(level = logging.ERROR)

И ваш предупреждения модуля будут полностью игнорироваться, в то время как любые сообщения ERROR или более высокого уровня из вашего модуля будут обрабатываться.

7
ответ дан Lav 31 August 2018 в 17:46
поделиться

Я не уверен, является ли решение питоновым или нет, но я использую его довольно часто с небольшими изменениями: парсер выполняет свою работу в генераторе и дает результаты и код состояния. Код приема принимает решения о том, что делать с несостоявшимися элементами:

def process_items(items)
    for item in items:
        try:
            #process item
            yield processed_item, None
        except StandardError, err:
            yield None, (SOME_ERROR_CODE, str(err), item)


for processed, err in process_items(items):
    if err:
       # process and log err, collect failed items, etc.
       continue
    # further process processed

. Более общий подход - практиковать использование шаблонов проектирования. Упрощенная версия Observer (при регистрации обратных вызовов для определенных ошибок) или вид Visitor (где у посетителя есть методы для обработки определенных ошибок, см. SAX для анализа) может быть ясным и понятным решением.

3
ответ дан newtover 31 August 2018 в 17:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: