В Python, как определить, является ли объект итеративным?

Истинная или False версия, основанная на ответе @DMfll:

try:
    # python2
    from urlparse import urlparse
except:
    # python3
    from urllib.parse import urlparse

a = 'http://www.cwi.nl:80/%7Eguido/Python.html'
b = '/data/Python.html'
c = 532
d = u'dkakasdkjdjakdjadjfalskdjfalk'

def uri_validator(x):
    try:
        result = urlparse(x)
        return result.scheme and result.netloc and result.path
    except:
        return False

print(uri_validator(a))
print(uri_validator(b))
print(uri_validator(c))
print(uri_validator(d))

Дает:

True
True
False
True
937
задан John Kugelman 12 November 2013 в 01:38
поделиться

7 ответов

  1. Проверка на __iter__ работает на типах последовательностей, но не работает, например, на строках на Python 2. Хотелось бы знать и правильный ответ, до тех пор есть одна возможность (которая работала бы и на строках):

     попробуйте:
     some_object_iterator = iter(some_object)
    за исключением TypeError как te:
     распечатать some_object, 'is not iterable'.
    

    Встроенный итер проверяет метод __iter__ или, в случае строк, метод __getitem__.

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

    Питонический стиль программирования, который определяет тип объекта, изучая его метод или атрибутную сигнатуру, а не явное отношение к какому-либо типу объекта ("Если он выглядит как утка и крякает как утка, то это должна быть утка"). Подчеркивая интерфейсы, а не конкретные типы, хорошо продуманный код повышает его гибкость, позволяя полиморфное замещение. Duck-типирование позволяет избежать использования тестов с помощью type() или isinstance(). Вместо этого обычно используется стиль программирования EAFP (Easier to Ask Forgiveness than Permission).

    ...

     try:
     _ = (e для e в моем_объекте)
    кроме TypeError:
     распечатать my_object, 'is not iterable'.
    
  3. Модуль Collections предоставляет некоторые абстрактные базовые классы, которые позволяют спрашивать у классов или экземпляров, предоставляют ли они определенную функциональность, например:

    из collection.abc import Iterable
    
    если это возможно:
     # e is iterable
    

    Однако это не проверяет на наличие классов, которые являются итерабельными через __getitem__.

805
ответ дан 19 December 2019 в 20:21
поделиться

В Python <= 2.5 вы не можете и не должны - итеративный интерфейс был «неформальным».

Но, начиная с Python 2.6 и 3.0, вы можете использовать новый ABC (абстрактный базового класса) вместе с некоторыми встроенными ABC, которые доступны в модуле коллекций:

from collections import Iterable

class MyObject(object):
    pass

mo = MyObject()
print isinstance(mo, Iterable)
Iterable.register(MyObject)
print isinstance(mo, Iterable)

print isinstance("abc", Iterable)

Теперь, желательно это или действительно работает, это просто вопрос соглашений. Как видите, вы можете зарегистрировать не повторяемый объект как Iterable - и это вызовет исключение во время выполнения. Следовательно, isinstance приобретает «новое» значение - он просто проверяет совместимость «объявленных» типов, что является хорошим вариантом для Python.

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

from collections import Iterable
from traceback import print_exc

def check_and_raise(x):
    if not isinstance(x, Iterable):
        raise TypeError, "%s is not iterable" % x
    else:
        for i in x:
            print i

def just_iter(x):
    for i in x:
        print i


class NotIterable(object):
    pass

if __name__ == "__main__":
    try:
        check_and_raise(5)
    except:
        print_exc()
        print

    try:
        just_iter(5)
    except:
        print_exc()
        print

    try:
        Iterable.register(NotIterable)
        ni = NotIterable()
        check_and_raise(ni)
    except:
        print_exc()
        print

Если объект не ' Чтобы удовлетворить ваши ожидания, вы просто выдаете ошибку TypeError, но если правильный ABC был зарегистрирован, ваша проверка бесполезна. Напротив, если доступен метод __ iter __ , Python автоматически распознает объект этого класса как Iterable.

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

22
ответ дан 19 December 2019 в 20:21
поделиться

Я нашел хорошее решение здесь:

isiterable = lambda obj: isinstance(obj, basestring) \
    or getattr(obj, '__iter__', False)
13
ответ дан 19 December 2019 в 20:21
поделиться

Можно попробовать так:

def iterable(a):
    try:
        (x for x in a)
        return True
    except TypeError:
        return False

Если мы можем сделать генератор, который итератует над ним (но никогда не используйте генератор, чтобы он не занимал много места), то он итерабельный. Похоже на "ду". Зачем вообще определять, является ли переменная итерабельной?

.
14
ответ дан 19 December 2019 в 20:21
поделиться
try:
  #treat object as iterable
except TypeError, e:
  #object is not actually iterable

Не проводите проверку, чтобы увидеть , действительно ли ваша утка , чтобы понять, является ли она пригодной для употребления или нет, обращайтесь с ней так, как если бы это было так, и жалуйтесь, если это не так

.
21
ответ дан 19 December 2019 в 20:21
поделиться

Этого недостаточно: объект, возвращаемый __iter__, должен реализовать протокол итерации (т.е. следующий метод). См. соответствующий раздел в документации .

На языке Python хорошая практика - "попробовать и посмотреть" вместо "проверить".

.
31
ответ дан 19 December 2019 в 20:21
поделиться

Утка печатает

try:
    iterator = iter(theElement)
except TypeError:
    # not iterable
else:
    # iterable

# for obj in iterator:
#     pass

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

Используйте Абстрактные базовые классы . Им нужна как минимум Python 2.6 и они работают только для классов нового стиля.

from collections.abc import Iterable   # import directly from collections for Python < 3.3

if isinstance(theElement, Iterable):
    # iterable
else:
    # not iterable

Однако, iter() немного надежнее, как описано в документации:

Проверка isinstance(obj, Iterable) обнаруживает классы, которые являются зарегистрированные как Iterable или имеющие метод __iter__(), но он не обнаруживает классы, которые итератируют с помощью __getitem__(). метод. Единственный надежный способ определить, является ли объект возможно ли вызвать iter(obj).

554
ответ дан 19 December 2019 в 20:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: