2010-05-30 2 views
43

В python есть простой способ сказать, что что-то не является последовательностью? Я попытался просто: if x is not sequence но питон не нравится, чтоPython: проверить, является ли объект последовательностью

+2

Связанный: В Python, как определить, является ли переменная Iterable? http://stackoverflow.com/questions/1952464/in-python-how-do-i-deetermine-if-a-variable-is-iterable/1952481#1952481 – miku

+7

Да, но, хотя все последовательности являются итерабельными, не все итерации последовательности (наборы и dicts являются встроенными итерабельными контейнерами, которые не являются последовательностями, например). –

ответ

57

iter(x) поднимет TypeError если x не может повторяться на - но что проверка «принимает» наборы и словари, хотя «отвергает» и другие не-последовательности таких как None и номера.

С другой рукой, строками (которые большинство приложений хотят рассматривать «отдельные элементы», а не последовательности) фактически являются последовательностями (так, любое испытание, если не specialcased строк, собирается подтвердить, что они есть) , Таким образом, таких простых проверок часто недостаточно.

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

>>> import collections 
>>> isinstance([], collections.Sequence) 
True 
>>> isinstance((), collections.Sequence) 
True 
>>> isinstance(23, collections.Sequence) 
False 
>>> isinstance('foo', collections.Sequence) 
True 
>>> isinstance({}, collections.Sequence) 
False 
>>> isinstance(set(), collections.Sequence) 
False 

Вы отметите строки еще считается «последовательность» (так как они являются ), но, по крайней мере, вы получите dicts и наборы из пути. Если вы хотите, чтобы исключить строки из вашей концепции «будучи последовательностей», вы могли бы использовать collections.MutableSequence (но это также исключает кортежи, которые, как струны, являются последовательности, но не являются изменяемыми), или сделать это явно:

import collections 

def issequenceforme(obj): 
    if isinstance(obj, basestring): 
     return False 
    return isinstance(obj, collections.Sequence) 

Сезон по вкусу и подача горячей! -)

+10

Обратите внимание, что этот пример кода возвращает неверный результат для объектов, которые реализуют протокол последовательности, но не включает ABC сборщиков. –

+4

Yep: иначе, чем простые ABC, Sequence не реализует метод класса '__subclasshook__', поэтому он никогда не будет автоматически распознавать класс, который решил не регистрировать его (или наследовать от него) - это было бы существенно невозможно для того, чтобы интроспекция сказать, принимает ли класс '__getitem__' целые числа и фрагменты, повышает индекс IndexError на неверные индексы и т. д. - все, что вам нужно, чтобы исключить' dict' и 'set', по существу (что _do_ похоже,« реализует последовательность протокол ", если вы просто занимаетесь самоанализом ... но потом не обращайтесь! -). –

+0

Наборы довольно легко исключить, поскольку они не имеют '__getitem__', но сопоставления намного сложнее. Лучшая проверка, которую я видел, - это, вероятно, поиск «ключей», например 'dict.update', но это все еще оставляет желать лучшего. – user2357112

4

Почему вы это делаете? Обычный способ здесь - потребовать определенный тип вещи (последовательность или число или файл-подобный объект и т. Д.), А затем использовать его, не проверяя ничего. В Python мы обычно не используем классы для переноса семантической информации, но просто используем определенные методы (это называется «утиная печать»). Мы также предпочитаем API, где мы точно знаем, чего ожидать; использовать аргументы ключевого слова, препроцессировать или определять другую функцию, если вы хотите изменить способ работы функции.

+3

Это ограничение задания. Если аргумент, который мы передали, не является int, long или sequence, нам нужно поднять 'TypeError' – nicotine

+1

@nicotine, признать, что это назначение указывает на дизайн, который обычно неидиоматичен и нестабилен. Рассмотрим нормальный случай, когда объект должен быть точно одним типом вещи. Если параметр должен быть последовательностью, но вы получаете int, когда вы индексируете или перебираете его, вы уже получите 'TypeError'. Аналогичным образом, если вы попытались выполнить целые операции с последовательностью, которую вы бы сделали. –

+0

Предоставление согласованного API (когда это вообще возможно), который ожидает только одного типа вещей, позволяет писать более простой код, который все еще вызывает ошибки, когда что-то идет не так, но более устойчиво, поскольку поддерживает типы, о которых вы не думали, но удовлетворяете истинным (например, некоторый пользовательский класс, который реализует '__len__' и' __getitem__', будет работать как последовательность.) –

6

Python 2.6.5 documentation описывает следующие типы последовательностей: string, Unicode string, list, tuple, buffer и xrange.

def isSequence(obj): 
    return type(obj) in [str, unicode, list, tuple, buffer, xrange] 
+14

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

+3

Кроме того, используйте 'isinstance' вместо' type' для поддержки подклассов. – bfontaine

-3

почему спрашивают, почему

попытаться получить длину и если исключение возвращают ложные

def haslength(seq): 
    try: 
     len(seq) 
    except: 
     return False 
    return True 
+1

«set» имеет длину, но не последовательность. – bfontaine

4

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

Последовательность имеет длину, имеет последовательность элементов и разрезание нарезания [doc]. Таким образом, это было бы так:

def is_sequence(obj): 
    t = type(obj) 
    return hasattr(t, '__len__') and hasattr(t, '__getitem__') 
    # additionally: and hasattr(t, '__setitem__') and hasattr(t, '__delitem__') 

Они все специальные методы, __len__() должен возвращать количество элементов, __getitem__(i) должен возвратить деталь (в последовательности это я ей вещь, но не с отображение), __getitem__(slice(start, stop, step)) должен возвращать подпоследовательность и __setitem__ и __delitem__, как вы ожидаете.Это такой договор, но действительно ли этот объект действительно или нет, зависит от того, соблюдает ли объект контракт или нет.

Примечание что функция выше также вернет True для отображения, например. dict, так как отображение также имеет эти методы. Чтобы преодолеть это, вы можете сделать тяжелее работы:

def is_sequence(obj): 
    try: 
     len(obj) 
     obj[0:0] 
     return True 
    except TypeError: 
     return False 

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

+0

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

+2

Если вы используете 'hasattr()', вам нужно проверить тип объекта для магических методов, а не самого объекта. См. [Python 2] (https://docs.python.org/2/reference/datamodel.html#special-method-lookup-for-new-style-classes) и [Python 3] (https: // docs .python.org/3/reference/datamodel.html # special-method-lookup) о том, как искать специальные методы. – augurar

+0

@augurar Спасибо, человек – BornToCode

4

Я думаю, что ниже фрагмент кода делает то, что вы хотите:

def is_sequence(obj): 
    return hasattr(type(obj), '__iter__') 
+2

Должно быть 'hasattr (type (obj), '__iter __')', см. [Этот комментарий] (https://stackoverflow.com/questions/2937114/#comment71833903_31043360). – augurar

 Смежные вопросы

  • Нет связанных вопросов^_^