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