Определение списка или кортежа в Python, исключая строки

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы провести проверку, является ли переменная obj списком или кортежем, используйте данную конструкцию с функцией isinstance(obj, (list, tuple)):

Python
Скопировать код
if isinstance(obj, (list, tuple)):
    print("Да, это список или кортеж, но никак не строка.")

TESCT. Этот метод коректно идентифицирует, относится ли объект к типам списков или кортежей, исключая тем самым строки, которые в Python 3 не являются подтипами tuple или list.

Кинга Идем в IT: пошаговый план для смены профессии

Не спешите судить об объекте по его типу: "Утиная" типизация и последовательности

Преимущества "утиной" типизации

В Python широко распространён принцип "утиной" типизации. Согласно ему, вместо того, чтобы проверять тип объекта, вы можете попытаться выполнить с ним операции и обработать возможные исключения:

Python
Скопировать код
try:
    obj[0]  # Попытка обращения к первому элементу
    print("Скорее всего, это список или кортеж.")
except (TypeError, IndexError):
    print("Какое-то несоответствие. Скорее всего, это не то, что нам нужно...")

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

Это птица? Это самолет? Нет, это последовательность!

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

Python
Скопировать код
if hasattr(obj, '__getitem__') and not isinstance(obj, str):
    print("Судя по всему, перед нами список или кортеж.")

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

Учтите особенности вашего Python: Совместимость версий

Минутка ностальгии: Python 2 и проверка строк

Если вы до сих пор используете Python 2, то для исключения строк вы могли бы проверить наличие типа basestring, который является родителем для str и unicode:

Python
Скопировать код
assert not isinstance(obj, basestring)  # Здесь мы говорим: "Извините, строк не обнаружено."

В Python 3 же вместо basestring используется просто str:

Python
Скопировать код
assert not isinstance(obj, str)

Абстрактные базовые классы: элегантный подход

Если у вас используется Python 3.8 или новее, вы можете стильно использовать collections.abc.Sequence для идентификации последовательностей, при этом не забудьте исключить строки:

Python
Скопировать код
from collections.abc import Sequence

if isinstance(obj, Sequence) and not isinstance(obj, str):
    print("Это последовательность, но ни в коем случае не строка.")

Будьте внимательны: начиная с Python 3.3 произошли некоторые изменения в абстрактных базовых классах модуля Collections.

С учётом необходимости скорости: Производительность

Гонка за производительностью

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

Специализированные функции для особых объектов

В некоторых случаях может быть разумным создать специализированные функции для различных типов, применяя isinstance для оптимизации в зависимости от типа объекта:

Python
Скопировать код
if isinstance(obj, tuple):
    # Функции для кортежей
elif isinstance(obj, list):
    # Функции для списков

Главное — помните, что не стоит увлекаться оптимизацией, рискуя при этом потерять гибкость Python.

Визуализация

Представьте, что у нас есть конвейер завешенный разными товарными позициями:

Markdown
Скопировать код
Конвейер (🚚): [📦, 📦, "📜", ("📄", "📄"), ["📦", "📦"]]
Python
Скопировать код
for item in conveyor_belt:
    if isinstance(item, (list, tuple)):
        print("Обнаружены списки или кортежи на конвейере! 📦➡️✅")
    else:
        print("Возможно, это не наш товар. 📜❌")

Результат проверки:

Markdown
Скопировать код
📦➡️✅: [📦, 📦]
📜❌: "📜"
📦➡️✅: ("📄", "📄")
📦➡️✅: ["📦", "📦"]

Главным для нас являются упаковки, то есть коробки и пакеты (списки и кортежи). Строки (бумага) нам не нужны!

Возможные проблемы: Подводные камни и специальные случаи

Маскирующиеся объекты

Берегитесь объектов, притворяющихся списками и кортежами: они могут успешно ввести вас в заблуждение, проявляя поведение, соответствующее протоколу __getitem__. Если это для вас критично, проверьте их на соответствие протоколам последовательностей.

Рекурсивная проверка: Внимание, рекурсия!

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

Изменения пространства имен: Приспособление к изменениям

Используя абстрактные базовые классы из модуля collections, принимайте во внимание совместимость с различными версиями Python.

Прагматический подход: функциональность превыше всего

Когда речь идет о том, чтобы определить, больше ли объект похож на список или кортеж, сфокусируйтесь на его функциональности, а не просто на типе. Проверьте наличие необходимых методов и соответствие ожидаемому поведению.