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

Есть ли способ, например isiterable? Единственным решением, которое я нашел до сих пор, является вызов

hasattr(myObj, '__iter__')

Но я не уверен, насколько это безупречно.

Ответ 1

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

    try:
        some_object_iterator = iter(some_object)
    except TypeError as te:
        print some_object, 'is not iterable'
    

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

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

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

    ...

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

    from collections.abc import Iterable
    
    if isinstance(e, Iterable):
        # e is iterable
    

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

Ответ 2

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

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__() итерацию с помощью __getitem__(). Единственный надежный способ определить, является ли объект итеративным, - это вызвать iter(obj).

Ответ 3

Я хотел бы пролить немного больше света на взаимодействие iter, __iter__ и __getitem__ и то, что происходит за кулисами. Вооружившись этими знаниями, вы сможете понять, почему лучшее, что вы можете сделать, это

try:
    iter(maybe_iterable)
    print('iteration will probably work')
except TypeError:
    print('not iterable')

Сначала я перечислю факты, а затем быстро напомню, что происходит, когда вы используете цикл for в python, а затем обсудите их, чтобы проиллюстрировать факты.

Факты

  1. Вы можете получить итератор из любого объекта o, вызвав iter(o), если выполняется хотя бы одно из следующих условий:

    a) o имеет метод __iter__, который возвращает объект итератора. Итератор - это любой объект с методом __iter__ и __next__ (Python 2: next).

    b) o имеет метод __getitem__.

  2. Проверка экземпляра Iterable или Sequence или проверка наличия атрибута __iter__ недостаточно.

  3. Если объект o реализует только __getitem__, но не __iter__, iter(o) создаст итератор, который пытается извлечь элементы из o по целочисленному индексу, начиная с индекса 0. итератор будет перехватывать любой IndexError (но не другие ошибки), который возникает, а затем сам вызывает StopIteration.

  4. В самом общем смысле, нет никакого способа проверить, является ли итератор, возвращенный iter нормальным, кроме как попробовать его.

  5. Если объект o реализует __iter__, функция iter обеспечит что объект, возвращаемый __iter__, является итератором. Там нет проверки вменяемости если объект только реализует __getitem__.

  6. __iter__ побеждает. Если объект o реализует как __iter__, так и __getitem__, iter(o) вызовет __iter__.

  7. Если вы хотите сделать свои собственные объекты итеративными, всегда наследуйте от абстрактного базового класса Iterable или одного из его подклассов. Вам придется либо реализовать метод __iter__, либо он будет предоставлен, как в случае Sequence.

Петли for

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

Когда вы используете for item in o для некоторого итерируемого объекта o, Python вызывает iter(o) и ожидает объект итератора в качестве возвращаемого значения. Итератор - это любой объект, который реализует метод __next__ (или next в Python 2) и метод __iter__.

По соглашению метод итератора __iter__ должен возвращать сам объект (т.е. return self). Затем Python вызывает next для итератора до тех пор, пока не будет вызвано StopIteration. Все это происходит неявно, но следующая демонстрация делает это видимым:

import random

class DemoIterable(object):
    def __iter__(self):
        print('__iter__ called')
        return DemoIterator()

class DemoIterator(object):
    def __iter__(self):
        return self

    def __next__(self):
        print('__next__ called')
        r = random.randint(1, 10)
        if r == 5:
            print('raising StopIteration')
            raise StopIteration
        return r

Итерация над DemoIterable:

>>> di = DemoIterable()
>>> for x in di:
...     print(x)
...
__iter__ called
__next__ called
9
__next__ called
8
__next__ called
10
__next__ called
3
__next__ called
10
__next__ called
raising StopIteration

Обсуждение и иллюстрации

По пунктам 1 и 2: получение итератора и ненадежные проверки

Рассмотрим следующий класс:

class BasicIterable(object):
    def __getitem__(self, item):
        if item == 3:
            raise IndexError
        return item

Вызов iter с экземпляром BasicIterable вернет итератор без проблем, потому что BasicIterable реализует __getitem__.

>>> b = BasicIterable()
>>> iter(b)
<iterator object at 0x7f1ab216e320>

Однако важно отметить, что b не имеет атрибута __iter__ и не считается экземпляром Iterable или Sequence:

>>> from collections import Iterable, Sequence
>>> hasattr(b, '__iter__')
False
>>> isinstance(b, Iterable)
False
>>> isinstance(b, Sequence)
False

Именно поэтому Fluent Python от Luciano Ramalho рекомендует вызывать iter и обрабатывать потенциал TypeError как наиболее точный способ проверить, является ли объект итеративным. Цитирую прямо из книги:

Начиная с Python 3.4, наиболее точный способ проверить, является ли объект x итеративным, - это вызвать iter(x) и обработать исключение TypeError, если это не так. Это более точно, чем использование isinstance(x, abc.Iterable), потому что iter(x) также учитывает устаревший метод __getitem__, а Iterable ABC - нет.

В пункте 3: перебираем объекты, которые предоставляют только __getitem__, но не __iter__

Перебор экземпляра BasicIterable работает как положено: Python создает итератор, который пытается извлечь элементы по индексу, начиная с нуля, пока не будет поднято IndexError. Метод демонстрационного объекта __getitem__ просто возвращает item, который был передан в качестве аргумента __getitem__(self, item) итератором, возвращенным iter.

>>> b = BasicIterable()
>>> it = iter(b)
>>> next(it)
0
>>> next(it)
1
>>> next(it)
2
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Обратите внимание, что итератор вызывает StopIteration, когда он не может вернуть следующий элемент, и что IndexError, который вызывается для item == 3, обрабатывается внутренне. Вот почему цикл по BasicIterable с циклом for работает, как и ожидалось:

>>> for x in b:
...     print(x)
...
0
1
2

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

class WrappedDict(object): # note: no inheritance from dict!
    def __init__(self, dic):
        self._dict = dic

    def __getitem__(self, item):
        try:
            return self._dict[item] # delegate to dict.__getitem__
        except KeyError:
            raise IndexError

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

>>> w = WrappedDict({-1: 'not printed',
...                   0: 'hi', 1: 'Qaru', 2: '!',
...                   4: 'not printed', 
...                   'x': 'not printed'})
>>> for x in w:
...     print(x)
... 
hi
Qaru
!

В пунктах 4 и 5: iter проверяет наличие итератора при вызове __iter__:

Когда iter(o) вызывается для объекта o, iter удостоверяется, что возвращаемое значение __iter__, если метод присутствует, является итератором. Это означает, что возвращаемый объект должен реализовать __next__ (или next в Python 2) и __iter__. iter не может выполнять какие-либо проверки работоспособности для объектов, которые только предоставить __getitem__, поскольку он не может проверить, доступны ли элементы объекта по целочисленному индексу.

class FailIterIterable(object):
    def __iter__(self):
        return object() # not an iterator

class FailGetitemIterable(object):
    def __getitem__(self, item):
        raise Exception

Обратите внимание, что создание итератора из экземпляров FailIterIterable завершается неудачно, а создание итератора из FailGetItemIterable завершается успешно, но при первом вызове __next__ будет выдано исключение.

>>> fii = FailIterIterable()
>>> iter(fii)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iter() returned non-iterator of type 'object'
>>>
>>> fgi = FailGetitemIterable()
>>> it = iter(fgi)
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/iterdemo.py", line 42, in __getitem__
    raise Exception
Exception

В пункте 6: __iter__ выигрывает

Этот прост. Если объект реализует __iter__ и __getitem__, iter вызовет __iter__. Рассмотрим следующий класс

class IterWinsDemo(object):
    def __iter__(self):
        return iter(['__iter__', 'wins'])

    def __getitem__(self, item):
        return ['__getitem__', 'wins'][item]

и вывод при зацикливании на экземпляр:

>>> iwd = IterWinsDemo()
>>> for x in iwd:
...     print(x)
...
__iter__
wins

В пункте 7: ваши итерируемые классы должны реализовывать __iter__

Вы можете спросить себя, почему большинство встроенных последовательностей, таких как list, реализуют метод __iter__, когда __getitem__ будет достаточно.

class WrappedList(object): # note: no inheritance from list!
    def __init__(self, lst):
        self._list = lst

    def __getitem__(self, item):
        return self._list[item]

В конце концов, итерация над экземплярами класса выше, который делегирует вызовы от __getitem__ до list.__getitem__ (используя квадратную скобку), будет работать нормально:

>>> wl = WrappedList(['A', 'B', 'C'])
>>> for x in wl:
...     print(x)
... 
A
B
C

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

  1. Если вы реализуете __iter__, экземпляры будут считаться итеративными, а isinstance(o, collections.abc.Iterable) вернет True.
  2. Если объект, возвращаемый __iter__, не является итератором, iter немедленно завершится ошибкой и вызовет TypeError.
  3. Специальная обработка __getitem__ существует по причинам обратной совместимости. Цитирую снова из Fluent Python:

Вот почему любая последовательность Python является итеративной: все они реализуют __getitem__. По факту, стандартные последовательности также реализуют __iter__, и ваш тоже должен, потому что специальная обработка __getitem__ существует по причинам обратной совместимости и может быть ушел в будущее (хотя это не устарело, как я пишу это).

Ответ 4

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

В Python хорошей практикой является "попытаться увидеть" вместо "проверки".

Ответ 5

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

Но поскольку 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 очень полезна.

Ответ 6

try:
  #treat object as iterable
except TypeError, e:
  #object is not actually iterable

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

Ответ 7

Лучшее решение, которое я нашел до сих пор:

hasattr(obj, '__contains__')

который в основном проверяет, реализует ли объект оператор in.

Преимущества (ни одно из других решений не имеет всех трех):

  • это выражение (работает как лямбда, в отличие от варианта try... except)
  • он (должен быть) реализован всеми повторами, включая строки (в отличие от __iter__)
  • работает на любом Python >= 2.5

Примечания:

  • философия Python "просить прощения, а не разрешения" не работает хорошо, когда, например, в списке у вас есть как итерации, так и non-iterables, и вам нужно обрабатывать каждый элемент по-разному в соответствии с его типом (обработка итераций на try и non-iterables, кроме того, будет работать, но будет выглядеть прикладом - уродливым и вводящим в заблуждение)
  • решения этой проблемы, которые пытаются на самом деле перебирать объект (например, [x для x в obj]), чтобы проверить, может ли он быть итерабельным, может вызвать значительные штрафы за производительность для больших итераций (особенно если вам просто нужны первые несколько элементов итерабельный, например) и его следует избегать

Ответ 8

Вы можете попробовать следующее:

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

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

Ответ 9

Начиная с Python 3.5 вы можете использовать модуль ввода из стандартной библиотеки для вещей, связанных с типами:

from typing import Iterable

...

if isinstance(my_item, Iterable):
    print(True)

Ответ 10

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

isiterable = lambda obj: isinstance(obj, basestring) \
    or getattr(obj, '__iter__', False)

Ответ 11

Согласно Глоссарию Python 2, итерации

все типы последовательностей (например, list, str и tuple) и некоторые непоследовательные типы, такие как dict и file а также объекты любых классов, которые вы определяете с помощью __iter__() или __getitem__(). Итерации можно использовать в цикле for и во многих других местах, где требуется последовательность (zip(), map(),...). Когда итеративный объект передается в качестве аргумента встроенной функции iter(), он возвращает итератор для объекта.

Конечно, учитывая общий стиль кодирования для Python, основанный на том факте, что "проще просить прощения, чем разрешения", общее ожидание заключается в использовании

try:
    for i in object_in_question:
        do_something
except TypeError:
    do_something_for_non_iterable

Но если вам нужно проверить это явно, вы можете проверить итерацию по hasattr(object_in_question, "__iter__") or hasattr(object_in_question, "__getitem__"). Вы должны проверить оба, потому что str не имеет метода __iter__ (по крайней мере, не в Python 2, в Python 3 они есть) и потому что у объектов generator нет метода __getitem__.

Ответ 12

Я часто нахожу удобным внутри своих скриптов определение функции iterable. (Теперь включает в себя Alfe предложил упрощение):

import collections

def iterable(obj):
    return isinstance(obj, collections.Iterable):

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

if iterable(obj):
    # act on iterable
else:
    # not iterable

как вы бы это сделали с помощью функции callable

EDIT: если у вас установлен numpy, вы можете просто: от numpy import iterable, который просто что-то вроде

def iterable(obj):
    try: iter(obj)
    except: return False
    return True

Если у вас нет numpy, вы можете просто реализовать этот код или выше.

Ответ 13

имеет встроенный так:

from pandas.util.testing import isiterable

Ответ 14

def is_iterable(x):
    try:
        0 in x
    except TypeError:
        return False
    else:
        return True

Это скажет "да" всем типам итерируемых объектов, но не укажет на строки в Python 2. (Это то, что я хочу, например, когда рекурсивная функция может принимать строку или контейнер строк. В этой ситуации просить прощения может привести к обфуску, и лучше сначала спросите разрешения.)

import numpy

class Yes:
    def __iter__(self):
        yield 1;
        yield 2;
        yield 3;

class No:
    pass

class Nope:
    def __iter__(self):
        return 'nonsense'

assert is_iterable(Yes())
assert is_iterable(range(3))
assert is_iterable((1,2,3))   # tuple
assert is_iterable([1,2,3])   # list
assert is_iterable({1,2,3})   # set
assert is_iterable({1:'one', 2:'two', 3:'three'})   # dictionary
assert is_iterable(numpy.array([1,2,3]))
assert is_iterable(bytearray("not really a string", 'utf-8'))

assert not is_iterable(No())
assert not is_iterable(Nope())
assert not is_iterable("string")
assert not is_iterable(42)
assert not is_iterable(True)
assert not is_iterable(None)

Многие другие стратегии здесь скажут "да" строкам. Используйте их, если вы хотите.

import collections
import numpy

assert isinstance("string", collections.Iterable)
assert isinstance("string", collections.Sequence)
assert numpy.iterable("string")
assert iter("string")
assert hasattr("string", '__getitem__')

Примечание: is_iterable() ответит да на строки типа bytes и bytearray.

  • bytes объекты в Python 3 являются итерабельными True == is_iterable(b"string") == is_iterable("string".encode('utf-8')) В Python 2 такого типа нет.
  • bytearray объекты в Python 2 и 3 являются итерабельными True == is_iterable(bytearray(b"abc"))

Подход O.P. hasattr(x, '__iter__') будет указывать да на строки в Python 3 и нет в Python 2 (независимо от того, '' или b'' или u''). Спасибо @LuisMasuelli за то, что он заметил, это также приведет вас к ошибкам __iter__.

Ответ 15

Это всегда ускользало от меня относительно того, почему в python есть callable(obj) → bool но не iterable(obj) → bool...
конечно, проще сделать hasattr(obj,'__call__') даже если он медленнее.

Так как почти каждый ответ рекомендует использовать try/except TypeError, где тестирование исключений обычно считается плохой практикой для любого языка, здесь есть реализация iterable(obj) → bool которую я полюбил и часто использую:

Ради Python 2 я буду использовать лямбду только для дополнительного повышения производительности...
(в python 3 не имеет значения, что вы используете для определения функции, def имеет примерно ту же скорость, что и lambda)

iterable = lambda obj: hasattr(obj,'__iter__') or hasattr(obj,'__getitem__')

Обратите внимание, что эта функция выполняется быстрее для объектов с __iter__ так как она не проверяет __getitem__.

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

Ответ 16

Самый простой способ, уважающий Python duck typing, заключается в том, чтобы поймать ошибку (Python прекрасно знает, чего он ожидает от объекта, чтобы стать итератор):

class A(object):
    def __getitem__(self, item):
        return something

class B(object):
    def __iter__(self):
        # Return a compliant iterator. Just an example
        return iter([])

class C(object):
    def __iter__(self):
        # Return crap
        return 1

class D(object): pass

def iterable(obj):
    try:
        iter(obj)
        return True
    except:
        return False

assert iterable(A())
assert iterable(B())
assert iterable(C())
assert not iterable(D())

Примечания

  • Не имеет значения, является ли объект неистребимым, или был реализован багги __iter__, если тип исключения тот же: в любом случае вы не сможете выполнить итерацию объекта.
  • Думаю, я понимаю вашу обеспокоенность: как callable существует как проверка, могу ли я также полагаться на утиную печать, чтобы поднять AttributeError, если __call__ не определен для моего объекта, но это не случай для повторной проверки?

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

Ответ 17

Функция isiterable в следующем коде возвращает True, если объект iserable. если он не повторяется, возвращает False

def isiterable(object_):
    return hasattr(type(object_), "__iter__")

Пример

fruits = ("apple", "banana", "peach")
isiterable(fruits) # returns True

num = 345
isiterable(num) # returns False

isiterable(str) # returns False because str type is type class and it not iterable.

hello = "hello dude !"
isiterable(hello) # returns True because as you know string objects are iterable

Ответ 18

Вместо проверки атрибута __iter__, вы можете проверить атрибут __len__, который реализуется каждым итерируемым встроенным python, включая строки.

>>> hasattr(1, "__len__")
False
>>> hasattr(1.3, "__len__")
False
>>> hasattr("a", "__len__")
True
>>> hasattr([1,2,3], "__len__")
True
>>> hasattr({1,2}, "__len__")
True
>>> hasattr({"a":1}, "__len__")
True
>>> hasattr(("a", 1), "__len__")
True

Не повторяемые объекты не будут реализовывать это по очевидным причинам. Однако, это не улавливает определенный пользователь итерируемых, которые не реализуют ее и не делать выражения генератора, который iter может иметь дело. Однако это можно сделать в строке, и добавление простой проверки or проверки выражений для генераторов решит эту проблему. (Обратите внимание, что при записи type(my_generator_expression) == generator будет генерироваться NameError. NameError обратитесь к этому ответу.)

Вы можете использовать GeneratorType из типов:

>>> import types
>>> types.GeneratorType
<class 'generator'>
>>> gen = (i for i in range(10))
>>> isinstance(gen, types.GeneratorType)
True

--- принял ответ утдемир

(Это делает его полезным для проверки, можете ли вы вызвать len на объекте.)

Ответ 19

Как-то поздно на вечеринку, но я задал себе этот вопрос и увидел это, а затем подумал об ответе. Я не знаю, если кто-то уже опубликовал это. Но, по сути, я заметил, что у всех итерируемых типов есть "getitem". Вот как вы можете проверить, является ли объект итеративным, даже не пытаясь. (Пун задумано)

def is_attr(arg):
    return '__getitem__' in dir(arg)

Ответ 20

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

>>> '__iter__' in dir('sds')
True
>>> '__iter__' in dir(56)
False
>>> '__iter__' in dir([5,6,9,8])
True
>>> '__iter__' in dir({'jh':'ff'})
True
>>> '__iter__' in dir({'jh'})
True
>>> '__iter__' in dir(56.9865)
False

Ответ 21

это работает с диктовками, содержащими итерации (список,...), которые могут содержать диктовки. Python 3 для Python 2 unicode также должны быть исключены из итерации. Также могут быть некоторые итерации, которые не работают, о которых я не знаю. (т.е. приведет к бесконечной рекурсии)

from collections.abc import Iterable

def deep_omit(d, keys):
    if isinstance(d, dict):
        for k in keys:
            d.pop(k, None)
        for v in d.values():
            deep_omit(v, keys)
    elif isinstance(d, Iterable) and not isinstance(d, str):
        for e in d:
            deep_omit(e, keys)

    return d

Ответ 22

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

temp= [1,2,3,4]
help(temp)

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

Примечание: это будет то, что вы будете делать вручную.