У меня есть конфигурация, которую я загрузил в dict
. Он содержит целое число config["logging"]["backup_count"]
. Однако type(config["logging"]["backup_count"])
возвращается object
. Итак, когда я собираюсь передать это в следующее:
TimedRotatingFileHandler(log_file, backupCount=config["logging"]["backup_count"], when = "midnight", interval=1)
mypy жалуется, что я пытаюсь поставить object
там, где ожидается int
. Конечно, это поправимо, добавив приведение типов:
TimedRotatingFileHandler(log_file, backupCount=int(str(config["logging"]["backup_count"])), when = "midnight", interval=1)
но это кажется неуклюжим. Должен ли я это делать?
Я новичок в mypy и пишу на Python. Я хотел бы знать правильный протокол для решения подобных проблем. В частности, следует ли мне выполнять приведение -to-str-to-int или что-то еще?
Обновлено: Должен ли я использовать TypedDict
? Если мой словарь считывается, например, из файла .toml
, есть ли простой способ создать из него TypedDict
с правильным набором текста (я заранее знаю, какие типы конфигурации должны быть)?
При запуске скрипта ошибок нет. Только ошибка при вызове mypy
в скрипте для проверки типа.
Если это так, то просто игнорируйте это.
Как config
определить? Вероятно, вы захотите определить один или несколько TypedDict
, чтобы mypy
точно знал, какой тип связан с каждой клавишей.
если type(thing)
возвращает object
во время выполнения, никакие «приведения» не превратят его в int
. Это не C++ или Java, где объект можно «воспринимать» как один из его суперклассов путем приведения - int
, будучи подклассом, может «делать все, что делает «объект», но у него есть больше вещей (например, наличие значения) . И type
всегда будет возвращать фактический класс экземпляра.
@jsbueno Полностью согласен, object
- это object
, он не может стать int
.
Ваша проблема связана только с проблемой проверки типов. Если TimedRotatingFileHandler.__init__()
может принимать object
вместо int
, тогда все в порядке. Вероятно, вы можете просто игнорировать проблемы проверки типов. Они предназначены для случаев, когда вызванные методы/функция на самом деле не принимают объект типа object
и приводят к TypeError
. Если это просто проблема с аннотацией типа, я предлагаю вам либо проигнорировать ее, либо изменить аннотацию на что-то вроде этого (учитывая, что TimedRotatingFileHandler
— это ваш собственный класс и, следовательно, вы можете его изменить):
def __init__(self, logfile: File, backupCount: int|object, *args, **kwargs):
# code here
Вы правы, у меня нет времени заниматься проверкой типов в моем словаре. TimedRotatingFileHandler
— не мой класс, и он отказывается принимать object
вместо int
вместо backupCount
. Я понял, что это можно исправить с помощью TypedDict
, но накладные расходы на эту работу кажутся невероятными.
Это устраняет неправильную проблему. TimedRotatingFileHandler
конкретно, что ему нужен int
. Вместо того, чтобы ослаблять это ограничение, вам следует убедиться, что mypy
знает точный тип config
.
@chepner Интересно, TimedRotatingFileHandler
— это библиотечный класс? Если это не собственный класс пользователя, то ваш ответ лучше моего. Однако, если это собственный класс OP, то лучше либо игнорировать проблему проверки типов, либо изменить аннотацию типа в определении класса, как указано в моем сообщении. Кроме того, я считаю, что аннотации типов только создают ненужный шум и проблемы, которые отвлекают программистов от реальных проблем, а не приносят никакой пользы. Это только мое мнение, конечно.
@wormram Можете ли вы сказать мне, что не так с моим ответом, который заслуживает того, чтобы его не приняли? Разве вы не говорили в предыдущем комментарии, что использование TypedDict
создает накладные расходы, а также что у вас нет на это времени?
Вам следует определить TypedDict
, которые точно определяют тип config["logging"]["backup_count"]
. Минимальная демонстрация:
from typing import TypedDict
class LoggingConfig(TypedDict):
backup_count: int
class Config(TypedDict):
logging: LoggingConfig
config: Config = {"logging": {"backup_count": 3}}
reveal_type(config["logging"]["backup_count"]) # int
Более быстрый обходной путь: если вы уверены, что config["logging"]["backup_cont"]
действительно является int
, просто скажите mypy
:
from typing import cast
TimedRotatingFileHandler(log_file, backupCount=cast(int, config["logging"]["backup_count"]), when = "midnight", interval=1)
(По-прежнему существуют накладные расходы на вызов cast
, но во время выполнения все, что он делает, — это возвращает второй аргумент, а не фактически создает новое значение int
. При проверке типа mypy
предполагает, что второй аргумент имеет тип, указанный первый.)
Я думаю, что ваш ответ просто слишком усложняет ситуацию. MyPy — это просто средство проверки типов, а не компилятор языка. Комментарий ОП подтвердил, что передача object
не вызовет ошибку, а это означает, что TimedRotatingFileHandler.__init__()
действительно может принять object
вместо int
, так что здесь нет проблем. Это не значит, что прохождение object
нарушит программу.
Некоторые люди иногда просто сосредотачиваются на ответе на конкретную проблему, о которой спрашивает спрашивающий, не осознавая, что эта проблема даже не существует и не имеет значения. В этих случаях лучшее решение или ответ — сообщить спрашивающему, что его проблемы не существует, чтобы он не увяз в подобных вещах и не тратил впустую много времени. Мой ответ основан на этом, в то время как ваш ответ - один из тех, кто отлично отвечает на проблему, но не понимает, что проблему (в данном случае написание жалоб на mypy) следует опустить/игнорировать.
Программирование — это решение реальных проблем, а не попытка написать лучший и наиболее полный код, удовлетворяющий всем программам проверки и линтерам, доступным в сети.
Кроме того, ваше решение может привести к тому, что программа будет работать немного медленнее, что приемлемо, если цель или причина важны, но неприемлемо, если оно просто удовлетворяет mypy или другие проблемы с типизацией. Обмануть средства проверки типов, заставив их поверить в то, что ваш тип правильный, не так хорошо, как передать все, что вы хотите, пока код работает (работает плавно, выполняет цель и свою работу и не вызывает ошибок ни сам по себе, ни TypeError
, выращенный питоном).
Написание дополнительных классов только с целью ограничения типов также загрязняет пространство имен. Это нормально для небольших программ, но не совсем хорошо, если программа большая, и вы делаете это для каждого параметра функций и методов.
Приведение типов — хорошая (а иногда и необходимая) концепция в других языках программирования, таких как Java или C, но абсолютно не необходимая в Python. Помните, что Python — это динамически типизированный язык, поэтому не применяйте статически типизированные языковые привычки к динамически типизированному языку. Это не очень хорошо подходит, просто создает проблемы и шум.
Есть ли там ошибка? Я имею в виду, можно ли запустить код Python без завершения с помощью
ValueError
,TypeError
или чего-то еще?