#python #class #metaclass #typechecking
#python #класс #метакласс #проверка типов
Вопрос:
Мне нужно проверить тип аргумента в __init__()
. Я сделал это таким образом:
class Matrix:
def __init__(self, matrix):
"""
if type(matrix) != list raise argument error
"""
if type(matrix) != list:
raise TypeError(f"Expected list got {type(matrix)}")
self.matrix = matrix
a = 5
new_matrix = Matrix(a)
Но когда TypeError
возникает __init__()
метод уже вызван. Мне интересно, как это сделать до того, как он будет вызван. Я считаю, что это можно было бы сделать с помощью metaclass
, чтобы «перехватить его» в какой-то момент и вызвать ошибку, но я не знаю как.
Комментарии:
1. Вы могли бы переопределить
__new__
; это вызывалось раньше__init__
. Но … почему?2. Зачем вам вообще нужно проверять тип аргумента? Это не путь утки … 🦆
3. @khelwood Ну, я подумал, что если бы у меня было много инициализации переменных и / или вызовов методов внутри
__init__()
таким образом, я мог бы «сэкономить время» и вызвать ошибку до того, как программа попадет во время выполнения (я думаю, что последнее тоже безопаснее).4.
__init__
также выполняется только во время выполнения.__new__
также. Если вы хотите проверить типы перед выполнением, вам необходимо использовать аннотации типов и инструмент статической проверки типов.5. @kaktus_car: Это не имеет смысла. Похоже, у вас может быть непонимание того, какой код выполняется, когда. Удаление этой проверки из
__init__
не сэкономит время.
Ответ №1:
Во-первых: обычно в Python такие проверки во время выполнения не выполняются — за исключением случаев, когда это строго необходимо. Идея в том, что все, что передается __init__
в этом случае, будет вести себя достаточно аналогично списку, чтобы использоваться вместо него. В этом и заключается идея «утиного ввода».
Второе: если эта проверка действительно необходима, то if
оператор внутри тела функции или метода, как и вы, является способом сделать это. Не имеет значения, что «метод был запущен, и внутри него возникла ошибка» — именно так работает динамическая типизация в Python.
В-третьих: на самом деле есть способ предотвратить вызов вашей программы __init__
с неправильным типом параметра, а именно использовать статическую проверку типов. Ваша программа выдает ошибку на этапах подготовки, когда вы запускаете средство проверки, например «mypy» — это примерно в тот же момент времени, когда некоторые статические языки выдают ошибку: когда они компилируются на явном шаге перед запуском. Статическая проверка типов может повысить безопасность, которая, по вашему мнению, вам нужна, но это совершенно новый мир шаблонов и бюрократии для кода на Python. Веб-поиск по запросу «проверка статического типа python» может перечислить вам некоторые моменты, которые вы можете начать изучать — вторая ссылка, которую я получаю, выглядит довольно интересной:https://realpython.com/python-type-checking /
Четвертое: если вы выбираете проверку на основе if, вам следует проверить, соответствует ли полученный вами объект «достаточному списку» для ваших целей, а не «type(a) != list». Это запретит подклассы списков. not isinstance(a, list)
примет подклассы списка, но заблокирует несколько других типов объектов, которые могли бы просто работать. В зависимости от того, что вы хотите, ваш код будет работать с любым типом «последовательности». В этом случае вы можете импортировать collections.abc.Sequence
и проверить, является ли ваш параметр экземпляром этого параметра вместо этого — это позволит пользователям вашего метода использовать любые классы, которые имеют длину и могут извлекать их по порядку.
И, просто повторяя это снова: нет абсолютно никаких проблем с выполнением этой проверки внутри метода. Это можно было бы учесть, создав сложный декоратор, который мог бы выполнять проверку типов — на самом деле существуют пакеты Python, которые могут использовать аннотации типов, точно так же, как они используются инструментами статической проверки типов, и выполнять проверки во время выполнения. Но это не даст вам никакого времени выполнения. Статическая проверка типа сделает это перед запуском, но, тем не менее, ресурсы, полученные при этом, незначительны.
И, наконец, нет, это не имеет ничего общего с метаклассом. Можно было бы использовать метакласс для добавления декораторов ко всем вашим методам и заставить эти декораторы выполнять проверку во время выполнения — но вы все равно можете просто использовать декоратор явно.
Комментарии:
1. Это отвечает на вопрос полностью и досконально. Очень полезно для такого ученика, как я, получить прямые указания, подобные этим. Большое спасибо