什么是容器和可迭代的对象(及生成器和迭代器)
#!/usr/bin/python3 # -*- coding:utf-8 -*- #Author:qika ''' 一. 容器 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取, 可以用in, not in关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中 (也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)在Python中,常见的容器对象有: list, deque... set, frozensets(不可变集合)... dict, defaultdict, OrderedDict, Counter... tuple, namedtuple... str 容器的概念就像一个盒子,可以往里面装东西.当它可以用来询问某个元素是否包含在其中时, 那么这个对象就可以认为是一个容器,比如 list,set,tuples都是容器对象: assert 1 in [1, 2, 3] # lists assert 4 not in [1, 2, 3] assert 1 in {1, 2, 3} # sets assert 4 not in {1, 2, 3} assert 1 in (1, 2, 3) # tuples assert 4 not in (1, 2, 3) 询问某元素是否在dict中用dict的中key: d = {1: 'foo', 2: 'bar', 3: 'qux'} assert 1 in d assert 'foo' not in d # 'foo' 不是dict中的元素 询问某substring是否在string中: s = 'foobar' assert 'b' in s assert 'x' not in s assert 'foo' in s 尽管绝大多数容器都提供了某种方式来获取其中的每一个元素,但这并不是容器本身提供的能力, 而是可迭代对象赋予了容器这种能力,当然并不是所有的容器都是可迭代的, 比如:Bloom filter,虽然Bloom filter可以用来检测某个元素是否包含在容器中, 但是并不能从容器中获取其中的每一个值,因为Bloom filter压根就没把元素存储在容器中, 而是通过一个散列函数映射成一个值保存在数组中。 二. 可迭代对象(iterable) 大部分对象都是可迭代,只要实现了__iter__方法的对象就是可迭代的。 __iter__方法会返回迭代器(iterator)本身,例如: lst = [1,2,3] lst.__iter__() <listiterator object at 0x7f97c549aa50> Python提供一些语句和关键字用于访问可迭代对象的元素,比如for循环、列表解析、逻辑操作符等。 判断一个对象是否是可迭代对象: from collections import Iterable # 只导入Iterable方法 isinstance('abc', Iterable) >>True isinstance(1, Iterable) >>False isinstance([], Iterable) >>True 这里的isinstance()函数用于判断对象类型。 可迭代对象一般都用for循环遍历元素,也就是能用for循环的对象都可称为可迭代对象。 例如,遍历列表: lst = [1, 2, 3] for i in lst: print i ''' #列表推导式 # a = [x for x in range(10)] # b = [x**2 for x in range(10)] # print(a) # print(b) #生成器 #可以理解为一种数据类型,自动实现迭代器协议 #生成器创建:2种方式 #第一种:(x for x in range(10)) #第二种:yield ''' #第一种方式: a = (x for x in range(10)) print(a)#会打印<generator object <genexpr> at 0x0000000001DE2E60>,即生成器对象 a1=a.__next__() #通过内置的方法__next__()进行获取值 print(a1)#打印值。但是始终都是默认获取的值是:0 #因此,如果想要迭代获取范围内所有的值,都是通过next()来获取 next(a)#获取第一次,获取的值为1 next(a)#值为2 #我临时插入做点其他的事情 print(“我临时做其他的事情”) next(a)#值为3--->> 这就是生成器的作用,虽然中途插入做了其他事情,但是我后面还是可以接着继续使用生成器函数 #第二种方式: def test(): print("one") yield 1 #yield 等同于 return 1 print("two") yield 2 #yield 等同于 return 2 t = test() print(t)#<generator object test at 0x0000000002132EB8> 会打印出这是个生成器对象 #获取值,该怎么做? print(next(t))#打印一次,默认获取第一个值:one,1 print(next(t))#打印第二次,获取值:two,2 #另:如果像上面那样仅仅使用next(t)不加print,那么就只会执行函数内的内容,而不会管yield #此时就不会管print出yield的内容(所以yield就如同函数的return) # next(t)#获取第一次,值:one # next(t)#获取第二次,值:two #总结:----------------------------------- #在调用生成器的过程中, # 每次遇到yield时函数会暂停并保存打印出当前所有的运行信息并返回yield的值。 #并在下一次执行next()方法时又继续运行后面的 ''' #send()方法 ''' def test(): print("one") count=yield 1 print(count) print("two") yield 2 t = test() #注意!!!使用send()传值时,需要有“变量”接收 t.send(None)#使用send时,第一次传值只能使用None,如同next(t) # print(t) t.send("aaa") ''' ############################################ ############################################## #迭代器
#定义: #生成器都是迭代器(而迭代器不一定是生成器 ) #python中的内部工具(如for循环,sum,min,max函数等)基于迭代器协议访问对象。 #作用: # 1、省内存,如果使用列表,计算值时会一次获取所有值,那么就会占用更多的内存。 # 而迭代器则是一个接一个计算,只能向前,不能反复 # 2、使代码更通用、更简单。 # 3、惰性机制 #如何判断是不是迭代器? #需满足两个条件:1、有iter方法。2、有next方法 #实例: #迭代器的对象内部定义了一个__iter__()方法 l=[1,2,3,4,5,6] d=iter(l) #即相等于 l.__iter__() print(next(d))#迭代打印l列表内的值:1 print(next(d))#迭代打印l列表内的值:2 print(next(d))#迭代打印l列表内的值:3 #--->>从上可见,在“满足有iter方法时,有next方法存在”时,就是一个迭代器对象了!!! #-->>那么如何通过for循环来遍历一个迭代器对象??? # 用while循环模拟for循环机制 li=[1,2,3,4,5,6] diedai_l = li.__iter__() while True: try: print(diedai_l.__next__()) except StopIteration: print("迭代完毕,循环终止") break """ for循环时: 1调用可迭代对象的iter方法并返回一个迭代器对象 2不断调用迭代器对象的next方法 3处理stopiteration这个报错信息(因为超出边界了,超出了范围,会自动停止) """ #最后,如何通过代码判断是否为迭代器对象呢? #--->>通过isinstance()方法来判断 from collections import Iterator print(isinstance(1,list))#会打印出False,因为1不是列表,即:可迭代对象 li=[1,2,3,4,5,6] print(isinstance(li,list))#判断li列表,是否为list可迭代对象-->>结果会打印出true