Как сделать проверку на тип данных в python

Обновлено: 07.07.2024

ТИПЫ ДАННЫХ В PYTHON

Кроме того, к базовым типам также относятся логический тип и тип NoneType.

Числа

Тип данных Числа имеет в Python три вида:

Целые числа

Примеры записи целых десятичных чисел:

Двоичные числа записывают с префиксом 0b.

Примеры записи целых двоичных чисел:

Восьмиричные числа записывают с префиксом 0o.

Примеры записи целых восьмиричных чисел:

Шестнадцатиричные числа записывают с префиксом 0x.

Примеры записи целых шестнадцатиричных чисел:

Дробные числа

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

Примеры записи дробных чисел:

Комплексные числа

Мнимая часть комплексного числа записывается с помощью постфикса j.

Примеры записи комплексных чисел:

Строки

Строки — это последовательности символов. Строки в Python записываются в кавычках. Можно использовать пару двойных кавычек или пару одинарных (апострофов).

Каждый символ в строке имеет свой индекс (номер). Нумерация начинается с нуля.

Примеры записи строк:

Списки

Списки — составной тип данных, состоящий из элементов, разделенных запятыми.

Элементы списка не обязательно должны быть одного типа. Элементом списка может быть даже другой список.

Списки в Python записываются в квадратных скобках. Каждый элемент в списке имеет свой индекс (номер). Нумерация начинается с нуля.

Кортежи

Кортежи очень похожи на списки, они состоят из элементов, разделенных запятыми.

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

Кортежи в Python записываются в круглых скобках. Каждый элемент в кортеже имеет свой индекс. Индексация начинается с нуля.

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

Множества

Множества являются неупорядоченным типом данных, который может хранить только уникальные значения. Все повторы автоматически удаляются.

Множества не поддерживают индексацию, то есть элементы множества не могут иметь индексов.

Множества удобны тем, что с ними можно выполнять операции объединения, пересечения, вычитания, сравнения (находить элементы множества, отсутствующие в другом множестве, или находить элементы множества, присутствующие в другом множестве).

Множества в Python записываются в фигурных скобках.

Элементами множества могут быть числа, строки, кортежи, но не могут быть списки, множества или словари.

Словари

Словари являются неупорядоченным типом данных и состоят из пар ключ-значение.

Используя ключи можно быстро получить значения из словаря (но не наоборот). Ключом может быть любой неизменяемый тип данных (число, строка, кортеж), а значением — любой тип данных.

Пары ключ, значение в словаре разделяются двоеточием и записываются через запятую.

Словари в Python записываются в фигурных скобках.

Ключи в словаре не должны повторяться. Если ключ повторится, то предыдущее значение из словаря будет удалено. Получим:

Логический тип

Логический тип (boolean) имеет два значения: истина (True) и ложь (False).

При преобразовании к логическому типу любой непустой и неравный нулю объект является истиной, а пустой или равный нулю — ложью.

Тип NoneType

Тип NoneType в Python принимает значение None, которое идентично значению Null в других языках программирования.

Проверка типа

Узнать тип объекта можно с помощью функции type().

Создадим строковый объект и напечатаем его тип. Получим:

Проверить тип объекта можно с помощью функции isinstance(). Функция принимает два аргумента: имя объекта и название типа. Если тип объекта и название типа совпадают, то функция возвратит логическое значение True, если не совпадают, то возвратит False.

Создадим целочисленный объект и напечатаем результат, возвращаемый функцией isinstance(). Получим: Попробуем еще. Получим:

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

Например, объявления переменных с типами в языках со статической типизацией, кроме своего основного назначения — инструкций компилятору или интерпретатору, ещё и помогают программисту лучше понимать написанный код, служат своеобразной документацией. Динамическая типизация не в состоянии этого дать.

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

По данным исследований StackOverflow за 2020, 2019, 2018, 2017, 2016, 2015 (там же можно посмотреть результаты за 2014 и 2013) годы, Python с каждым годом растёт в популярности.

Сегодня на Python написано много сложных систем из сотен файлов и сотен тысяч строк кода. В таких обстоятельствах документирующее свойство системы типов становится очень полезным. В достаточно крупной кодовой базе при отсутствии информации о типах очень сложно угадать (а только гадать и остаётся), какие же именно объекты циркулируют по программе.

Кроме того, даже если код без информации о типах может быть и вполне понятен человеку, например, благодаря удачно выбранным именам, то для автоматики — это в любом случае абсолютно непроницаемый черный непрозрачный ящик. В такой ситуации очень сложно, не выполняя код (мы же говорим про статический анализ), понять как он будет вести себя в ран-тайме. Аннотации типов позволяют IDE, линтерам и тайп-чекерам лучше понимать код программы, что дает возможность рано отлавливать достаточно хитрые ошибки. В конечном итоге это делает написанные программы надежнее.

По этим соображениям, в Python 3.5 появился специальный синтаксис для объявления типов параметров функций и их возвращаемых значений (PEP 484). В Python 3.6 эта возможность была расширена — стало можно объявлять типы переменных вообще в любом месте программы (PEP 526). С каждой новой версией языка эта функциональность улучшается, и писать аннотации типов становится всё проще, удобнее и естественнее, а экосистема вокруг типизированного Python развивается семимильными шагами.

Нужно отметить, что тайп-аннотации — это именно возможность, а не обязанность. У программиста есть выбор — добавлять информацию о типах или нет. Таким образом Python пытается усидеть на двух стульях — остаться языком с динамической типизацией и дать возможность для статического анализа написанных программ. Привнести в хаос немного порядка, так сказать. И, по-моему, у Python это неплохо получается.

Программист при написании кода расставляет информацию о типах переменных, параметров и возвращаемых значений функций. Это никак не влияет на выполнение программы. Python сам по себе никак не использует эту информацию в ран-тайме, он лишь перекладывает её в специальные атрибуты функций или переменных, делая доступной для сторонних утилит. То есть, если указано, что функция принимает строки, то это никак не помешает вызвать её с целыми числами или списками — в зависимости от тела функции, она может отработать, а может завершиться ошибкой, но сама возможность вызова с любыми типами аргументов никак не ограничивается.

Зачем же тогда писать тайп-аннотации?

  • документация для разработчиков;
  • сторонние утилиты и библиотеки могут использовать эту информацию по своему усмотрению, например, выполняя проверки типов или приводя данные к нужному типу.

Первый пункт достаточно очевидный, а про второй мы поговорим чуть позже в разделе про тайп-чекеры.

Вот так, например, можно тайп-аннотировать простую функцию:

Типы параметров, принимаемых функцией, записываются после имени параметра через знак двоеточия, но перед значением по умолчанию, если оно присутствует. Возвращаемое значение функции записывается после знака “стрелки”.

Теперь читатель просто взглянув на сигнатуру функции может понять, что функция принимает строку и возвращает строку. Наверное, если передать в неё другой тип, то она не сможет корректно отработать.

Точно так же можно использовать для тайп-аннотаций и любые другие базовые (примитивные, не-контейнерные) типы в Python: int , float , bool , str , bytes , None и вообще практически что угодно. Чуть позже посмотрим, как типизировать контейнерные типы данных, такие как списки, кортежи, словари и множества.

Вот так можно зааннотировать функцию, которая принимает два числа с плавающей точкой и возвращает число с плавающей точкой:

А вот так функцию, которая принимает строку и булевый аргумент, но ничего не возвращает:

Вот так можно аннотировать любые переменные в любом месте кода (Python 3.6+):

Если мы создадим свой класс, то его тоже можно использовать для аннотаций:

Перейдем к более сложным типам, таким как списки, кортежи, словари и множества. Можно аннотировать в лоб, используя сами имена классов:

Это не слишком информативно, потому что кроме самого типа контейнера было бы ещё полезно знать, какие данные он в себе содержит. Что такое person_info ? Кортеж чего?

В Python до версии 3.9 для этого придётся использовать отдельные классы из модуля typing , потому что стандартные классы не представляют такой функциональности. Делается это при помощи квадратных скобок, как будто мы извлекаем что-то по индексу:

Начиная с Python 3.9 можно использовать стандартные классы в точно таких же целях, ничего ниоткуда не импортируя:

Согласитесь, так намного понятнее. Сразу видно, какой тип данных лежит внутри контейнера. Такие типы называются обобщёнными (generic types).

Кстати, в типизации можно яснее увидеть разницу между тем как должны использоваться списки и кортежи ( list vs. tuple ).

  • Списки содержат однородные данные — они все должны быть одного типа, иначе с таким списком будет тяжеловато работать.
  • Кортеж, напротив, может содержать разнородные данные, которые в зависимости от позиции могут иметь тот или иной тип.
  • Список нужно использовать, когда длина заранее неизвестна либо она переменна, например, список пользователей.
  • Кортеж нужно использовать, когда длина данных известна заранее и строго фиксирована, например, как в записи из таблицы в СУБД.

Получается, кортеж — это не просто неизменяемый брат-близнец списка.

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

Часто случаются ситуации, когда нужно объединить несколько типов, например, для того, чтобы указать, что функция может принимать и строки, и числа. Этого можно достичь при помощи дженерик-типа Union из модуля typing :

Также очень часто возникает ситуация, когда возможно либо значение определенного типа, либо None . Это настолько частая ситуация, что для этого даже сделали отдельный дженерик-тип Optional :

Также может возникнуть ситуация, когда не получается указать какой-либо конкретный тип, потому что, например, функция может принимать на вход абсолютно что угодно. Для этих случаев тоже есть специальный объект typing.Any :

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

Вообще советую заглянуть в документацию модуля typing , там есть много интересных классов на все случаи жизни.

Допустим, что тайп-аннотации написаны. Как начать получать от этого пользу?

В экосистеме Python есть несколько конкурирующих между собой тайп-чекеров, например, mypy , pyre , pytype , pyright . Самым популярным среди них является mypy , наверное, потому что одним из ключевых его разработчиков является сам Гвидо ван Россум. Давайте на mypy и остановимся.

Установим mypy в проект. Внутри виртуального окружения проекта нужно выполнить:

Для pipenv и poetry соответственно вот так:

Давайте напишем самый тривиальный пример программы с ошибкой:

При выполнении, очевидно, программа завершится ошибкой:

Давайте посмотрим, сможет ли тайп-чекер обнаружить эту проблему:

Отлично! Не исполняя программу, mypy смог понять, что в ней присутствует ошибка. Давайте запрячем эту же самую ошибку чуть глубже, используя функцию:

Проверим типы в этой программе:

Тайп-чекер пропустил правильный вызов функции, но обнаружил вызов функции с ошибкой.

Тайп-аннотации — это настолько круто и удобно, что, честно говоря, я уже плохо представляю, как раньше (до Python 3.5) без этого люди вообще программировали. Для меня это самый веский аргумент в пользу Python 3 и против Python 2. Это незаменимый инструмент при разработке насколько-нибудь крупной программы.

Обязательно нужно интегрировать тайп-чекинг в свой редактор/IDE, чтобы ошибки подсвечивались ещё на этапе написания кода. Можно интегрировать тайп-чекинг в Git-хуки и CI.

На странице "Awesome Python Typing" можно найти ещё много полезных инструментов, которые пользуются тайп-аннотациями.

Если понравилась статья, то подпишитесь на уведомления о новых постах в блоге, чтобы ничего не пропустить!


Python - это язык с динамической типизацией, и типы данных переменных выводятся без явного вмешательства разработчика.

Если бы у нас был код, который нуждался в списке, но не имел подсказок типа, которые не являются обязательными, как мы можем избежать ошибок, если используемая переменная не является списком?

В этой статье, мы будем разбирать то как проверить, является ли переменная списком в Python, используя функции type() и isinstance() , а также оператора is

Разработчики обычно используют type() и is , хотя они могут быть ограничены в определенных контекстах, в этом случае лучше использовать функцию isinstance() .

Проверьте, является ли переменная списком с type()

Встроенная функция type() может использоваться для возврата типа данных объекта. Давайте создадим Dictionary, Tuple и List и воспользуемся функцией type() , чтобы проверить, является ли переменная list или нет:

Теперь, чтобы программно изменить поток кода на основе результатов этой функции:

Проверьте, является ли переменная списком с оператором is

Оператор is используется для сравнения идентичностей в Python. Другими словами, он используется для проверки того, относятся ли два объекта к одному и тому же месту в памяти.

Результат type(variable) всегда будет указывать на то же место в памяти, что и класс этого variable . Итак, если мы сравним результаты функции type() в нашей переменной с классом list , он вернет True если наш variable является списком.

Взглянем на оператора is :

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

Теперь они должны вернуть тот же номер:

Примечание. Если вы выбрали этот подход, следует помнить о любых подтипах. Если вы сравните результат type() любого подтипа списка с классом list , он вернет False , даже если переменная - это список, хотя и является его подклассом.

Этот недостаток оператора is исправлен в следующем подходе - с помощью функции isinstance() .

Проверьте, является ли переменная списком с помощью isinstance()

Функция isinstance() - еще одна встроенная функция, которая позволяет вам проверять тип данных переменной. Функция принимает два аргумента - переменную, тип которой мы проверяем, и тип, который мы ищем.

Эта функция также принимает во внимание подклассы, поэтому любые подклассы list также будут возвращать True для экземпляра класса list .

Давайте попробуем это с помощью обычного list и UserList из фреймворка collections :

Выполнение этого кода приводит к:

Вывод

Python - это язык с динамической типизацией, и иногда из-за ошибки пользователя мы можем иметь дело с неожиданным типом данных.

В этом руководстве мы рассмотрели три способа проверить, является ли переменная списком в Python - функцией type() , оператором is и функцией isinstance() .

В этой статье мы поговорим, как определить тип переменной в Python. Заодно, расскажем, почему одни переменные считают изменяемыми, а другие нет. И какие тут существуют тонкости, связанные с терминологией.

В некоторых случаях нужно определить тип данных переменной в Python. Проверить, к какому типу принадлежит та или иная переменная, можно посредством функции type:

Также мы можем определить тип данных переменной в Python посредством функции isinstance() :

Здесь стоит обратить внимание, что isinstance() в отличие от type даёт возможность проверять тип данных на принадлежность хотя бы одному типу из кортежа, который передан в качестве 2-го аргумента:

Также следует упомянуть и другое, не менее значимое достоинство isinstance() — поддержка наследования. Для isinstance() экземпляр производного класса является экземпляром его базового класса:

Проверка типов

Есть и ещё кое-что: во время преобразования типов данных переменных в Python нередко возникают следующие ошибки:

Впрочем, ошибка является вполне логичной, ведь мы пробуем преобразовать в десятичный формат строку „a“.

Понятно, что на практике вы с такой ошибкой не столкнётесь. Однако бывает, что надо, к примеру, пробежаться по списку строк, преобразовав в числа те, которые уже содержат числа. Чтобы ошибки избежать, нужно сначала определить, с каким типом переменных мы имеем дело.

В Python соответствующие средства, конечно, имеются. К примеру, используя метод isdigit() , мы определим, состоит ли наша строка из одних только цифр:

Есть и ещё один метод — isalpha() . Он проверит, состоит ли наша строка из одних лишь букв:

А вот isalnum() определит, состоит ли наша строка из цифр или букв:

Но давайте снова вернёмся к упомянутой в начале статьи функции type. Порой, в зависимости от результата, функция или библиотека может выводить различные типы объектов. К примеру, если объект только один, то возвращается строка, а если их несколько, то нам возвращается кортеж. Мы же хотим построить ход программы по иному, с учётом того, что было возвращено: строка либо кортеж. И здесь как раз и пригодится type:

То же самое и с кортежем, и с иными типами данных:

Неизменяемые и изменяемые данные в Python

Считается, что все типы данных в языке программирования Python можно отнести к любой из двух категорий: — изменяемые (mutable); — неизменяемые (unmutable).

И многие из предопределённых типов являются типами неизменяемых объектов: — символьные строки (class 'str'); — числовые данные (int, float, complex); — кортежи (tuple).

Что касается других типов, то они определены как изменяемые: — множества (set), — списки (list), — словари (dict).

Кроме того, вновь определяемые пользователем классы (типы) тоже можно определить как изменяемые или неизменяемые. И вообще, изменяемость объектов какого-нибудь типа считается принципиально значимой характеристикой, которая определяет, способен ли объект такого типа выступать в виде ключа для словарей (dict) либо нет.

К примеру строка s = 'abcdef' относится к неизменяемому типу, ведь в Python нельзя (это вам не C/C++) поменять какой-нибудь одиночный символ в строке, допустим, через s[ 2 ] = 'z', и это не говоря о том, чтобы вставить символ внутрь строки. Однако мы можем сделать s = s[ :2 ] + 'z' = s[ 3: ] и получить в итоге нужную строку 'abzdef', но это будет абсолютно другая строка, размещённая по абсолютно другому адресу в памяти, то есть s — переустановленная ссылка на новую строку. Однако поменять строку либо её длину (структурность) по текущей ссылке нельзя. В этом, как раз, и заключается неизменяемость объекта — неконстантность, ведь его значение поменять можно, однако это уже будет ссылка на другой объект с новым значением.

На этом всё, если хотите прокачать навыки Python-программирования "по-врослому", записывайтесь на курсы в OTUS:

Как узнать тип переменной: 32-разрядная без знака, 16-разрядная со знаком и т. Д.?

Как мне это увидеть?

Используйте type() встроенную функцию:

Чтобы проверить, принадлежит ли переменная данного типа, используйте isinstance :

Обратите внимание, что Python не имеет те же типы, что и C / C ++, что кажется вашим вопросом.

Возможно, вы ищете встроенную функцию . type()

Большое положительное целое число:

Отрицательное целое число:

Буквенная последовательность символов:

Целое число с плавающей точкой:

Мне пришлось дважды взять, когда я увидел это. Java SE8 теперь содержит целые числа без знака, и я настолько развил их, что кажется греховным, что у Java никогда не было целых чисел без знака до SE8.

Это так просто. Вы делаете это так.

Так что если у вас есть переменная, например:

Вы хотите знать его тип?

В Python есть правильные и неправильные способы делать практически все. Вот правильный путь:

использование type

Вы можете использовать __name__ атрибут, чтобы получить имя объекта. (Это один из немногих специальных атрибутов, для которого нужно использовать __dunder__ имя, чтобы добраться до него - в inspect модуле даже нет метода для него .)

Не использовать __class__

В Python имена, начинающиеся с подчеркиваний, семантически не являются частью общедоступного API, и пользователям рекомендуется избегать их использования. (За исключением случаев, когда это абсолютно необходимо.)

Так как type дает нам класс объекта, мы должны избегать его получения напрямую. :

Обычно это первая идея, которую люди имеют при доступе к типу объекта в методе - они уже ищут атрибуты, поэтому тип кажется странным. Например:

Не. Вместо этого, введите (self):

Детали реализации целых и чисел

Как узнать тип переменной: 32-разрядная без знака, 16-разрядная со знаком и т. Д.?

В Python эти особенности являются деталями реализации. Итак, в общем, мы обычно не беспокоимся об этом в Python. Однако, чтобы удовлетворить ваше любопытство .

В Python 2 int обычно представляет собой целое число со знаком, равное ширине слова реализации (ограничено системой). Это обычно реализуется как долго C . Когда целые числа становятся больше этого значения, мы обычно конвертируем их в длинные Python (с неограниченной точностью, не путать с длинными C).

Например, в 32-битном Python 2 мы можем вывести, что int является 32-битным целым числом со знаком:

В Python 3 старый int исчезает, и мы просто используем (Python) long как int, который имеет неограниченную точность.

Мы также можем получить некоторую информацию о числах с плавающей точкой в ​​Python, которые обычно реализуются как двойные в C:

Вывод

Не используйте __class__ семантически непубличный API для получения типа переменной. Используйте type вместо этого.

И не беспокойтесь о деталях реализации Python. Я сам не сталкивался с проблемами вокруг этого. Вы, вероятно, тоже не будете, и если вы действительно это сделаете, вы должны знать достаточно, чтобы не искать этот ответ для того, что делать.

Читайте также: