Я утверждаю, что это не может быть проверено статически в общем случае.
Рассмотрим следующий фрагмент кода:
d = datetime.strptime(read_date_from_network(), read_format_from_file())
Этот код может быть полностью действительным, где оба read_date_from_network
и read_format_from_file
действительно возвращают строки в нужном формате - или они могут быть тотальным мусор, как возвращение None или некоторые дерьмо. Независимо от того, что информация может быть определена только, будет определена во время работы - следовательно, статическая проверка бесполезна.
Более того, учитывая нынешнее определение datetime.strptime, даже если мы были с использованием статически типизированный язык, мы не смогли бы поймать эту ошибку (за исключением очень специфических случаев) - причина в том, что сигнатуру этой функции обречено нас с самого начала:
classmethod datetime.strptime(date_string, format)
в этом определении, date_string
и format
оба струны, несмотря на то, что они на самом деле имеют особое значение. Даже если мы что-то аналогичное в статически типизированных языках, как это:
public DateTime strpTime(String dateString, String format)
Компилятор (и линта и всех остальных) еще только видит:
public DateTime strpTime(String, String)
Это означает, что ни один из следующих не различимы друг от друга:
strpTime("%B %d, %Y", "January 8, 2014") // strpTime(String, String) CHECK
strpTime("January 8, 2014", "%B %d, %Y") // strpTime(String, String) CHECK
strpTime("cat", "bat") // strpTime(String, String) CHECK
Это не означает, что она не может быть сделано на всех - есть существуют некоторые линты для статически типизированных языков, таких как Java/C++/и т. д. который будет проверять строковые литералы, когда вы передаете их некоторым конкретным функциям (например, printf и т. д.).), но это можно сделать только тогда, когда вы вызываете эту функцию напрямую с литеральной строкой формата. В первом случае, который я представил, те же линтеры становятся столь же беспомощными, потому что просто неизвестно, будут ли строки правильного формата.
т.е. пуха может быть в состоянии предупредить об этом:
// Linter regex-es the first argument, sees %B et. al., warns you
strpTime("%B %d, %Y", "January 8, 2014")
, но он не смог бы предупредить об этом:
strpTime(scanner.readLine(), scanner.readLine())
Теперь, то же самое можно сконструировать в питона linter, но я не считаю, что это было бы очень полезно, потому что функции были первоклассными, поэтому я мог легко победить (гипотетический python) linter, написав:
f = datetime.strptime
d = f("January 8, 2014", "%B %d, %Y")
А потом мы снова снова очень хорошо.
Бонус: Что пошло не так
Проблема здесь состоит в том, что datetime.strptime
дает скрытое значение для каждой из этих строк, но не на поверхность этой информации в систему типа. Что можно было сделать, так это дать двум строкам разные типы - тогда могла бы быть больше безопасности, хотя бы за счет некоторой простоты использования.
например (с использованием ПЭП 484 аннотаций типа, a real thing!):
class DateString(str):
pass
class FormatString(str):
pass
class datetime(date):
...
def strptime(date_string: DateString, format: FormatString) -> datetime:
# etc. etc.
Тогда было бы начать быть выполнимо, чтобы обеспечить хорошее пылеобразования в общем случае - хотя DateString и классы FormatString должны были бы заботиться проверки их ввода, потому что снова система типов не может ничего сделать на этом уровне.
Послесловие:
Я думаю, что лучший способ справиться с этим, чтобы избежать этой проблемы, используя strftime
метод, который привязан к конкретному объекту даты и времени, и принимает только строковый формат аргумента. Это обходит всю проблему, предоставляя нам сигнатуру функции, которая не режет нас, когда мы обнимаем ее. Ура.
alecxe, как правило, если мы хотим преобразовать строку в datetime, мы будем использовать strptime() для конкретной строки, кроме strptime, мы можем проверить строку с регулярными выражениями, если данная строка находится в правильном формате datetime или нет, но это потребуется больше шаблонов регулярных выражений для проверки. – MicroPyramid