什么是容器和可迭代的对象(及生成器和迭代器)

#!/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

 

posted on 2020-12-12 22:27  QiKa  阅读(176)  评论(0编辑  收藏  举报