Как проверить, является ли объект списком или кортежем (но не строкой)?

Это то, что я обычно делаю, чтобы удостовериться, что вход представляет собой list / tuple но не str . Потому что много раз я наткнулся на ошибки, когда функция передает объект str по ошибке, а целевая функция делает for x in lst считая, что lst на самом деле является list или tuple .

 assert isinstance(lst, (list, tuple)) 

Мой вопрос: есть ли лучший способ достичь этого?

  • Последний Измененный загруженный файл не соответствует его HTTP-заголовку
  • Чтение двоичного файла .dat в виде массива
  • Обработка произвольного исключения, печать сообщения об исключении по умолчанию
  • urlencode массив значений
  • Django self join, Как преобразовать этот запрос в запрос ORM
  • Как получить сторонние файлы cookie?
  • Не удается получить привязки python ZeroMQ для получения сообщений по IPC
  • Python Tornado - асинхронный запрос блокирует
  • 13 Solutions collect form web for “Как проверить, является ли объект списком или кортежем (но не строкой)?”

    я думаю

     assert not isinstance(lst, basestring) 

    На самом деле вы хотите, иначе вы пропустите много вещей, которые действуют как списки, но не являются подклассами list или tuple .

    Помните, что в Python мы хотим использовать «утиную типизацию». Итак, все, что действует как список, можно рассматривать как список. Итак, не проверяйте тип списка, просто посмотрите, действует ли он как список.

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

    Вот функция, которую я написал для удовольствия. Это специальная версия repr() которая печатает любую последовательность в угловых скобках ('<', '>').

     def srepr(arg): if isinstance(arg, basestring): # Python 3: isinstance(arg, str) return repr(arg) try: return '<' + ", ".join(srepr(x) for x in arg) + '>' except TypeError: # catch when for loop fails return repr(arg) # not a sequence so just return repr 

    Это чисто и элегантно, в целом. Но что это isinstance() проверить делать? Это что-то вроде взлома. Но это важно.

    Эта функция вызывает себя рекурсивно на все, что действует как список. Если бы мы не обрабатывали строку специально, тогда ее рассматривали бы как список и разделили бы по одному символу за раз. Но тогда рекурсивный вызов будет пытаться рассматривать каждого персонажа как список – и он будет работать! Даже односимвольная строка работает как список! Функция будет продолжать вызывать себя рекурсивно до переполнения стека.

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

    Примечание: try / except – самый чистый способ выразить наши намерения. Но если этот код был каким-то критическим по времени, мы могли бы захотеть заменить его каким-то тестом, чтобы увидеть, является ли arg последовательностью. Вместо того, чтобы тестировать тип, мы должны, вероятно, тестировать поведение. Если у него есть метод .strip() , это строка, поэтому не рассматривайте ее как последовательность; в противном случае, если он является индексируемым или итерируемым, это последовательность:

     def is_sequence(arg): return (not hasattr(arg, "strip") and hasattr(arg, "__getitem__") or hasattr(arg, "__iter__")) def srepr(arg): if is_sequence(arg): return '<' + ", ".join(srepr(x) for x in arg) + '>' return repr(arg) 

    EDIT: Я изначально написал выше с проверкой на __getslice__() но я заметил, что в документации модулей модулей интересным является __getitem__() ; это имеет смысл, вот как вы индексируете объект. Это кажется более фундаментальным, чем __getslice__() поэтому я изменил это.

     H = "Hello" if type(H) is list or type(H) is tuple: ## Do Something. else ## Do Something. 
     import collections if isinstance(obj, collections.Sequence) and not isinstance(obj, basestring): print "obj is a sequence (list, tuple, etc) but not a string or unicode" 

    Для Python 3 обратите внимание на документы :

    Изменено в версии 3.3: Перемещенные коллекции Абстрактные базовые классы для модуля collection.abc. Для обратной совместимости они продолжают оставаться видимыми и в этом модуле.

    Python с PHP-вкусом:

     def is_array(var): return isinstance(var, (list, tuple)) 

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

    Это звучит как риторический вопрос, но это не так. Ответ на вопрос: «Почему я должен проверять тип аргумента?» вероятно, собирается предложить решение реальной проблемы, а не воспринимаемую проблему. Почему это ошибка, когда строка передается функции? Кроме того: если это ошибка, когда строка передается этой функции, является ли она также ошибкой, если какой-либо другой non-list / tuple iterable передан ей? Почему или почему нет?

    Я думаю, что наиболее распространенным ответом на вопрос будет то, что разработчики, которые пишут f("abc") , ожидают, что функция будет вести себя так, как если бы они написали f(["abc"]) . Вероятно, существуют обстоятельства, когда имеет смысл защищать разработчиков от самих себя, чем для поддержки использования итерации по символам в строке. Но сначала я подумал бы об этом.

    Объект str не имеет атрибута __iter__

     >>> hasattr('', '__iter__') False 

    так что вы можете сделать чек

     assert hasattr(x, '__iter__') 

    и это также повысит приятный AssertionError для любого другого неистребимого объекта.

    Изменить: Как упоминает Тим ​​в комментариях, это будет работать только в python 2.x, а не 3.x

    Это не предназначено для прямого ответа на OP, но я хотел поделиться некоторыми связанными идеями.

    Я был очень заинтересован в ответе @steveha выше, который, казалось, привел пример, где печатание утки, кажется, ломается. Однако, во-вторых, его пример подсказывает, что печатание на утике трудно соответствовать, но это не означает, что str заслуживает какой-либо специальной обработки.

    В конце концов, не- str тип (например, определяемый пользователем тип, который поддерживает некоторые сложные рекурсивные структуры), может вызвать функцию @steveha srepr чтобы вызвать бесконечную рекурсию. Хотя это, по общему признанию, маловероятно, мы не можем игнорировать эту возможность. Поэтому, а не специальную srepr str в srepr , мы должны уточнить, что мы хотим, чтобы srepr сделал, когда результат бесконечной рекурсии.

    Может показаться, что один разумный подход состоит в том, чтобы просто разбить рекурсию в srepr на list(arg) == [arg] srepr list(arg) == [arg] . Фактически, это полностью решило бы проблему с str , без каких-либо isinstance .

    Однако, действительно сложная рекурсивная структура может вызвать бесконечный цикл, где list(arg) == [arg] никогда не произойдет. Поэтому, хотя вышеуказанная проверка полезна, ее недостаточно. Нам нужно что-то вроде жесткого предела глубины рекурсии.

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

    Я делаю это в своих тестах.

     def assertIsIterable(self, item): #add types here you don't want to mistake as iterables if isinstance(item, basestring): raise AssertionError("type %s is not iterable" % type(item)) #Fake an iteration. try: for x in item: break; except TypeError: raise AssertionError("type %s is not iterable" % type(item)) 

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

    Я нахожу такую ​​функцию с именем is_sequence в тензорном потоке .

     def is_sequence(seq): """Returns a true if its input is a collections.Sequence (except strings). Args: seq: an input sequence. Returns: True if the sequence is a not a string and is a collections.Sequence. """ return (isinstance(seq, collections.Sequence) and not isinstance(seq, six.string_types)) 

    И я проверил, что он отвечает вашим потребностям.

    Просто сделайте это

     if type(lst) in (list, tuple): # Do stuff 

    Я, как правило, делаю это (если я действительно должен был это делать):

     for i in some_var: if type(i) == type(list()): #do something with a list elif type(i) == type(tuple()): #do something with a tuple elif type(i) == type(str()): #here's your string 

    Если у вас уже есть панды, вы можете просто сделать это:

     variable = pd.Series(variable).tolist() 

    Это то, что я делаю, чтобы обеспечить список.

    Python - лучший язык программирования в мире.