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

234

В Python, как лучше всего проверить, содержит ли переменная список или кортеж? (т.е. коллекция)

Является ли isinstance()зло, как предлагается здесь? http://www.canonical.org/~kragen/isinstance/

Обновление: наиболее распространенная причина, по которой я хочу отличить список от строки, это когда у меня есть какое-то неопределенно глубокое вложенное дерево / структура данных списков списков строк и т. Д., Которые я изучаю с помощью рекурсивного алгоритма, и мне нужно чтобы знать, когда я нажал на "лист" узлы.

Interstar
источник
72
Широко отвергать проверку типов как зло немного поверхностно. Это часть языка. Если это так плохо, кто-то должен написать PEP, чтобы удалить его.
Адам Кроссленд
4
@ Adam Crossland: «Это часть языка». Так же, как деление на ноль. Этого можно избежать. В этом случае без дополнительной информации это, вероятно, совершенно не нужно. Большая часть проверки типов в Python не нужна. Поскольку не все излишне, должна присутствовать некоторая проверка типов. Но это не значит, что это полезно, ценно или даже хорошая идея.
S.Lott
11
Итак, вы говорите, что требуется некоторая проверка типов, но, несмотря на это, это бесполезно, бесполезно и плохая идея. Извините, это просто не имеет смысла.
Гленн Мейнард
18
«ХХХ - это зло» - плохо продуманное, вводящее в заблуждение сокращение для «того, как вы просите сделать ХХХ, говорит о том, что вы не понимаете, когда его следует использовать, и вы почти наверняка хотите чего-то другого». Это, скорее всего, случай здесь.
Гленн Мейнард
2
Я не считал это злом. Я написал небольшое эссе о том, когда это зло и когда это оправдано. В этом эссе может быть много вещей - правильных, неправильных, ясных, расплывчатых, приятных, скучных - но одной вещью, которой это не является, является широкое отклонение техники.
Краген Хавьер Ситакер

Ответы:

101

Идите и используйте, isinstanceесли вам это нужно. Это несколько плохо, поскольку исключает пользовательские последовательности, итераторы и другие вещи, которые вам могут понадобиться. Однако иногда вам нужно вести себя иначе, если кто-то, например, передает строку. Мое предпочтение было бы явно проверить strили unicodeвот так:

import types
isinstance(var, types.StringTypes)

NB Не принимайте types.StringTypeза types.StringTypes. Последний включает в себя strи unicodeобъекты.

typesМодуль рассматривается многими устаревшими в пользу просто проверка непосредственно против типа объекта, так что если вы не хотите использовать выше, вы можете альтернативно проверить явно против strи unicode, как это:

isinstance(var, (str, unicode)):

Редактировать:

Еще лучше:

isinstance(var, basestring)

Конец редактирования

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

Видите, что «зло» в проверке типов заключается не в том, что вы, возможно, захотите вести себя по-разному для определенного типа объектов, а в том, что вы искусственно ограничиваете свою функцию от правильных действий с неожиданными типами объектов, которые в противном случае сделали бы правильные вещи. Если у вас есть последний запасной вариант, который не проверен, вы удалите это ограничение. Следует отметить, что слишком большая проверка типов является запахом кода, который указывает на то, что вы, возможно, захотите провести некоторый рефакторинг, но это не обязательно означает, что вы должны избегать его из getgo.

jcdyer
источник
2
Модуль типов - это немного исторического артефакта. Как упомянуто на docs.python.org/dev/library/types.html#module-types, если вы действительно должны проверить strтип, вы должны просто использовать его напрямую, вместо того, чтобы использовать types.StringTypeкоторый является просто псевдонимом для него. Но я не думаю, что этот ответ отвечает на заданный вопрос, потому что это было о «коллекции». Если вы не используете Python достаточно новый, чтобы иметь abcмодуль, который вы не можете использовать isinstanceдля проверки, и даже тогда я бы рекомендовал избегать проверки, если это вообще возможно.
MZZ
1
assert isinstance(u'abc', str) == False, Я согласен , что лучше проверить по типу непосредственно, а не с помощью typesмодуля, но types.StringTypesделает то , что strне делает: он возвращает истину strи unicodeобъекты. Я отредактирую свой ответ, чтобы предложить двойную проверку в качестве альтернативы.
jcdyer
1
Я понимаю, что не ответил непосредственно на вопрос проверки коллекций, но на самом деле был задан вопрос: «Является ли isinstanceзло?» И я привел встречный пример, который (1) является использованием без зла isinstance, потому что запасной вариант означает, что он не нарушает ducktyping, и (2) является хорошим решением для очень распространенной мотивации людей, желающих проверить, что-то listили tuple(то есть, чтобы избавиться от них из строк).
jcdyer
Я согласен с предостережением, что часто пользовательские типы также могут вести себя как строки. Но ОО Питона заходит так далеко ...
Краген Хавьер Ситакер
Делай class Foo(str): passчто хочешь?
jcdyer
569
if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'
ВАЛЛ
источник
1
Кажется, не работает: type ([]) ==> list; type ([]) is list ===> False
sten
3
В Python 2.7.5: type([]) is listвозвращаетсяTrue
Дэвид Гейгер
54
type(x) in [list,tuple]короче
Алекс Холкомб
если x и тип (x) указаны в списке: чтобы избежать несоответствия []
Кеничи Сибата
Я должен был прокрутить вниз так сильно. : D
Ритвик
38

Там нет ничего плохого в использовании, isinstanceесли это не избыточно. Если переменная должна быть только списком / кортежем, документируйте интерфейс и просто используйте его как таковой. В противном случае проверка вполне разумна:

if isinstance(a, collections.Iterable):
    # use as a container
else:
    # not a container!

У этого типа проверки есть несколько хороших сценариев использования, например, со стандартными строками метода beginwith / ndswith (хотя, если быть точным, они реализованы в C в CPython с использованием явной проверки, чтобы увидеть, является ли это кортежем - есть более одного способа чтобы решить эту проблему, как указано в статье, на которую вы ссылаетесь).

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

Скотт Гриффитс
источник
15
Это хороший способ проверить, является ли переменная итеративной. Тем не менее, это, вероятно, не будет работать для целей этого вопроса. Имейте в виду, что строка тоже итеративна и, вероятно, создаст ложное срабатывание.
Кори О.
setОбъект также итератор, который означает , что в то время как вы можете , конечно , поп - элементы, но это не гарантирует определенный порядок, который является очень опасной вещью для некоторых алгоритмов. В тех случаях, когда порядок элементов имеет значение, алгоритм, использующий этот фрагмент, потенциально может генерировать разные результаты на разных прогонах!
Ку
14

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

Игнасио Васкес-Абрамс
источник
12

Как насчет hasattr(a, "__iter__"):?

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

user1914881
источник
Я нашел это действительно полезным.
Джавадба
8
Также результаты True для строк (по крайней мере, на Python 3).
SzieberthAdam
2
Это неправильный ответ. Так как тип 'str' также имеет метод ' iter '. @SzieberthAdam был прав. Тип 'set' также является итеративным, но не подлежит упорядочению.
PADYMKO
Тоже есть __iter__.
изолейцин
Если вы продолжите, любой пользовательский тип может иметь __iter__по какой-то причине ...
Александр Ирбис
10

В Python 2.8 type(list) is listвозвращается, false
я бы предложил сравнить тип таким ужасным способом:

if type(a) == type([]) :
  print "variable a is a list"

(по крайней мере, в моей системе, используя anaconda в Mac OS X Yosemite)

Xanderite
источник
1
Имеет ли тип (a) list также значение false?
Дмитрий Синцов
4
Вы имели в виду Python 2.7.8? python.org/dev/peps/pep-0404/#official-pronouncement
Карл
Здравствуйте, мне любопытно: почему вы считаете свой пример "ужасным"?
Сет Коннелл
type(list) is listвозвращается, Falseпотому что type(list)есть type, а не list. type(list()) is listили с любым другим экземпляром списка вернется True.
Майкл Грин
8

Python использует «типизацию утки», то есть, если переменная похожа на утку, это должна быть утка. В вашем случае вы, вероятно, хотите, чтобы он был повторяемым, или хотите получить доступ к элементу по определенному индексу. Вы должны просто сделать это: т.е. использовать объект внутри for var:или var[idx]внутри tryблока, и если вы получите исключение, это не утка ...

Wim
источник
7
Проблема в том, что если varитерация строки произойдет, возможно, с неожиданными результатами.
Брайан М. Хант
Несмотря на факт, заявленный Брайаном М. Хантом, его решение довольно питоническое, с точки зрения просьбы о прощении, а не о разрешении.
Géza Török
6
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
tetra5
источник
3

Если вам просто нужно знать, можете ли вы использовать foo[123]нотацию с переменной, вы можете проверить наличие __getitem__атрибута (то, что Python вызывает при доступе по индексу) с помощьюhasattr(foo, '__getitem__')

Джефф Риди
источник
2

Должен быть более сложный тест, если вы действительно хотите обрабатывать что-либо как аргумент функции.

type(a) != type('') and hasattr(a, "__iter__")

Хотя обычно достаточно просто объяснить, что функция ожидает повторяемость, а затем выполнить только проверку type(a) != type('').

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

ZXX
источник
2

Другой простой способ узнать, является ли переменная списком или кортежем или вообще проверить тип переменной:

    def islist(obj):

        if ("list" in str(type(obj)) ): return True

        else : return False
Махди Омидиян
источник
1

В принципе, я согласен с Игнасио выше, но вы также можете использовать тип, чтобы проверить, является ли что-то кортежем или списком.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')
Адам Кроссленд
источник