Как эффективно проверять разные форматы даты при конвертации месяца в число - PullRequest
0 голосов
/ 28 июня 2019

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

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

Я попытался изменить порядок try-excepts, удалив строку-to-int, чтобы она была в блоке try-Кроме, не углубляясь в форматирование даты в исключении, но это все. Функция ниже - лучшая попытка, которую я имел. Я не мог думать ни о чем другом, кроме, может быть, создать вспомогательные функции?

Код

def get_start_month_updated():
    date_formats = ['%b', '%B']
    while True:
        month = input("What is the starting month?")
        try:
            month_num = int(month)
            if 1 <= month_num <= 12:
                return month_num
        except ValueError:
            for date_format in date_formats:
                try:
                    month_num = strptime(month, date_format).tm_mon
                    return month_num
                except ValueError:
                    pass
            else:
                print("You must enter a valid month")
        else:
            print("You must enter a valid month")

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

1 Ответ

1 голос
/ 28 июня 2019

Во-первых, вы должны создать функцию parse_month для лучшего тестирования. Эта parse_month функция может иметь несколько внутренних анализаторов, по одному для каждого формата: «int», datetime с «% b», datetime с «% B». Это деталь реализации.

Один из способов сделать это может быть:

import datetime
import functools


def parse_month(value):
    def from_int(v):
        month_num = int(v)
        if 1 <= month_num <= 12:
            return month_num
        raise ValueError(v)

    def from_month_fmt(fmt, v):
        return datetime.datetime.strptime(v, fmt).month

    parsers = (
        from_int,
        functools.partial(from_month_fmt, "%b"),
        functools.partial(from_month_fmt, "%B"),
    )
    for parser in parsers:
        try:
            return parser(value)
        except ValueError:
            pass
    else:
        raise ValueError(value)

Затем вы можете использовать эту функцию, чтобы запросить у пользователя:

def get_start_month_updated():
    while True:
        month = input("What is the starting month?")
        try:
            month_num = parse_month(month)
        except ValueError:
            print("You must enter a valid month")
        else:
            return month_num

Если вы не хотите изобретать велосипед, Arrow ваш друг:

import arrow

def parse_month(value):
    formats = (
        "MMMM",
        "MMM",
        "MM",
        "M"
    )
    for fmt in formats:
        try:
            return arrow.get(value, fmt).month
        except arrow.parser.ParserError:
            pass
    else:
        raise ValueError(value)
...