from collections.abc import Iterable # import directly from collections for Python < 3.3
if isinstance(the_element, Iterable):# iterableelse:# not iterable
from collections import Iterablefrom traceback import print_exc
def check_and_raise(x):if not isinstance(x, Iterable):raise TypeError, "%s is not iterable" % xelse: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
class A(object):def __getitem__(self, item):return something
class B(object):def __iter__(self):# Return a compliant iterator. Just an examplereturn iter([])
class C(object):def __iter__(self):# Return crapreturn 1
class D(object): pass
def iterable(obj):try:iter(obj)return Trueexcept:return False
assert iterable(A())assert iterable(B())assert iterable(C())assert not iterable(D())
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)) # tupleassert is_iterable([1,2,3]) # listassert is_iterable({1,2,3}) # setassert is_iterable({1:'one', 2:'two', 3:'three'}) # dictionaryassert 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 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 StopIterationreturn r
在DemoIterable上迭代:
>>> di = DemoIterable()>>> for x in di:... print(x)...__iter__ called__next__ called9__next__ called8__next__ called10__next__ called3__next__ called10__next__ calledraising StopIteration
讨论和插图
关于第1点和第2点:获得迭代器和不可靠的检查
考虑以下类:
class BasicIterable(object):def __getitem__(self, item):if item == 3:raise IndexErrorreturn item
>>> 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
class FailIterIterable(object):def __iter__(self):return object() # not an iterator
class FailGetitemIterable(object):def __getitem__(self, item):raise Exception
>>> 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 ExceptionException
fruits = ("apple", "banana", "peach")isiterable(fruits) # returns True
num = 345isiterable(num) # returns False
isiterable(str) # returns False because str type is type class and it's not iterable.
hello = "hello dude !"isiterable(hello) # returns True because as you know string objects are iterable
>>> '__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
>>> from faker import Faker>>> fake = Faker()>>> iter(fake) # No exception, must be iterable<iterator object at 0x7f1c71db58d0>>>> list(fake) # OoopsTraceback (most recent call last):File "<stdin>", line 1, in <module>File "/home/.../site-packages/faker/proxy.py", line 59, in __getitem__return self._factory_map[locale.replace('-', '_')]AttributeError: 'int' object has no attribute 'replace'
from collections.abc import Iterablemyobject = 'Roster'
if isinstance(myobject , Iterable):print(f"{myobject } is iterable")else:print(f"strong text{myobject } is not iterable")