使用dir()我们可以知道这个数据类型的内置函数有什么方法:

print(dir(int))  
print(dir(bool))
print(dir([]))
print(dir({}))
print(dir(set))

1.迭代器

iterable:可迭代的

迭代就是将数据能够一个一个按顺序取出来

s = 'abc'
print('__iter__' in dir(s)) #True
li = [1,2]
print('__iter__' in dir(li)) #True
b = False
print('__iter__' in dir(b)) #False
i = 123
print('__iter__' in dir(i)) #False
dic = {}
print('__iter__' in dir(dic)) #True
set1 = set()
print('__iter__' in dir(set1)) #True

上面数据类型返回为真说明它是可以迭代的,反之是不可迭代的

可迭代协议:

就是内部要有一个__iter__()来满足要求

当一个具有可迭代的数据执行__iter__()它将返回一个迭代器的内存地址

print('abc'.__iter__()) #<str_iterator object at 0x005401F0>

这里的iterator的意思是迭代器

迭代器协议:

现在有一个列表我们来看看它本身和在执行了__iter__()之后的方法有什么不同:

li = [1,2,3,'a']
print(dir(li)) #['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
print(dir(li.__iter__())) #['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
'''求两者的差集'''
print(set(dir(li.__iter__())) - set(dir(li))) #{'__length_hint__', '__setstate__', '__next__'}
__length_hint__()的作用是求元素的长度
__setstate__()的作用是指定索引值从哪里开始迭代
__next__()的作用可以让值一个一个的取出

在之前用到的for循环我们就是用__next__()这种方法进行取值,现在我们可以模拟for来写一个函数:
li = [1,2,3,'a']
def getItem(li):
iterator = li.__iter__()
while True:
print(iterator.__next__())
getItem(li)
#
#
#
# a
#StopIteration 如果找不到元素就会报错

如何处理掉这个异常?

li = [1,2,3,'a']
def getItem(li):
iterator = li.__iter__()
while True:
try:
print(iterator.__next__())
except StopIteration:
break
getItem(li)
#
#
#
# a

迭代器遵循迭代器协议:必须要有__iter__()和__next__()

迭代器的好处:

  a.从容器类型中一个一个的取值,会把所有的值都取到

  b.节省内存的空间

     迭代器并不会在内存中占用一大块内存,而是随着循环每次生成一个,每一次使用__next__()来给值

range():

print(range(10000000))  #range(0, 10000000)

实际上range()在调用的时候并没有真正生成这么多的值,如果真的生成的话那么内存可能会溢出

print('__iter__' in dir(range(10)))     #True
print('__next__' in dir(range(10))) #False
from collections import Iterable
from collections import Iterator
print(isinstance(range(10),Iterable)) #True 是一个可迭代对象
print(isinstance(range(10),Iterator)) #False 在执行后得到的结果并不是一个迭代器

迭代器总结:

1.可以被for循环的都是可迭代的

2.可迭代的内部都有__iter__()方法

3.只要是迭代器一定可以迭代

4.可迭代的变量.__iter__()方法可以得到一个迭代器

5.迭代器中的__next__()方法可以一个一个的获取值

6.for循环实际上就是在使用迭代器

2.生成器

生成器函数

本质上就是我们自己写的函数,只要含有yield关键字的函数就是生成器函数,yield不能和return共用且需要写在函数内部

def generator():        #生成器函数
print('a')
yield 5
ret = generator() #ret是一个生成器
print(ret) #<generator object generator at 0x00503F00>

生成器函数每次执行的时候会得到一个生成器作为返回值

如果要返回函数值:

def generator():        #生成器函数
print('a')
yield 5
print('b')
yield 4
g = generator() #g是一个生成器
print(g) #<generator object generator at 0x00503F00>
ret = g.__next__()
print(ret) #a
#
print('---------')
ret = g.__next__()
print(ret) #b
#

执行顺序:

使用for循环遍历生成器:

def generator():        #生成器函数
print('a')
yield 5
print('b')
yield 4
print('c')
yield 6
g = generator() #g是一个生成器
for i in g:
print(i)
# a
#
# b
#
# c
#

send():

send()和__next__()都有获取下一个值的功能,但send()在获取下一个值的时候可以给上一个yield的位置传递一个数据,让用户进行接收

send()在使用时需注意在第一次使用生成器时需用__next__()获取下一个值并且最后一个yield不能接受外部的值

def generator():         #生成器函数
print('a') #
content = yield 1 #
print(content,'= 1') #
print('b') #
content2 = yield 2 #
print(content2,'= 2')#
yield 3 # g = generator() #生成器g
ret = g.__next__() #执行1和2的右边语句
print(ret) #返回yield的值1
ret = g.send('a') #传递给yield一个值'a'让content接收,然后执行3,4语句
print(ret) #返回yield的值2
ret = g.send('b') #传递给yield一个值'b'让content2接收,然后执行6语句 yield再返回一个值3
print(ret)
# a
#
# a = 1
# b
#
# b = 2
#

移动平均值例子:

def average():          #定义一个平均值的生成器函数
sum = 0
count = 0
avg = 0
while True:
num = yield avg
sum += num
count += 1
avg = sum/count avg_g = average() #取得生成器
avg_g.__next__()
avg1 = avg_g.send(int(input())) #
avg1 = avg_g.send(int(input())) #
print(avg1) #

预激装饰器的生成器

def wrapper(func):
def inner(*args,**kwargs):
g = func(*args,**kwargs)
g.__next__()
return g
return inner
@wrapper #wrapper = wrapper(func)
def avgerage():
sum = 0
count = 0
avg = 0
while True:
num = yield avg
sum += num
count += 1
avg = sum/count
avg_g = avgerage()
print(avg_g.send(10))
print(avg_g.send(20))
print(avg_g.send(30))

yiled form

如何将字符串一个一个的去返回?

一般方法:

def generator():
a = 'abcde'
b = 'efdgh'
for i in a:
yield i
for i in b:
yield i
g = generator()
for i in g:
print(i)

用yiled form:

def generator():
a = 'abcde'
b = 'efdgh'
yield from a
yield from b
g = generator()
for i in g:
print(i)
# a
# b
# c
# d
# e
# e
# f
# d
# g
# h

监听文件例子:

def tail(filename):
f = open(filename,encoding='utf-8')
while True:
line = f.readline()
if line.strip():
yield line.strip()
g = tail('tail')
for i in g:
if 'python' in i:
print('******',i)
# ****** python
# ****** asd python

3.推导式

优点:基本不消耗内存

语法:以列表推导式为例

   (1)遍历元素进行挨个处理:[每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型]  

   (2)筛选功能:[满足条件的元素的相关操作 for 元素 in 可迭代数据类型 if 元素相关的条件]

1.列表推导式

li = [i*i for i in range(5)]
print(li) #[0, 1, 4, 9, 16]

找到50以内能被5整除的数:

li = [i for i in range(50) if i % 5 == 0]
print(li) #[0, 5, 10, 15, 20, 25, 30, 35, 40, 45]

找到两个列表中都含有一个'x'的元素

names = [['xasd','12sa','xa'],['','','x233']]
li = [name for lst in names for name in lst if name.count('x') == 1]
print(li) #['xasd', 'xa', 'x233']

2.生成器推导式

g = (i*2 for i in [1,5,6,7])
print(g) #<generator object <genexpr> at 0x006E4F00>
for i in g:
print(i)
#
#
#
#

3.字典推导式

将字典的键值互换

dict = {'key1' : 'value1','key2' : 'value2','key3' : 'value3'}
print(dict) #{'key3': 'value3', 'key2': 'value2', 'key1': 'value1'}
new_dict = {dict[i] : i for i in dict}
print(new_dict) #{'value2': 'key2', 'value1': 'key1', 'value3': 'key3'} 

合并大小写对应的value值,再将键都统一成小写

dict = {'a' : 1,'b' : 2,'A' : 3,'c' : 4}
new_dict = {k.lower() : dict.get(k.lower(),0) + dict.get(k.upper(),0) for k in dict} #如果没有找到这个值就返回0
print(new_dict) #{'c': 4, 'b': 2, 'a': 4}

4.集合推导式

具有去重复的功能

set = {x**2 for x in range(-5,6)}
print(set) #{0, 1, 4, 9, 16, 25}

4.相关面试题

例一:

def generator():
for i in range(4):
yield i g = generator()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1)) #[0, 1, 2, 3]
print(list(g2)) #[] 因为g2是往g1去拿值,但是g1已经从g用for循环遍历完了值,所以g2是一个空的列表

例二:

def add(n,i):
return n+i
def test():
for i in range(4): #0 1 2 3
yield i
g = test()
for n in [1,10]:
g = (add(n,i) for i in g)
'''
n = 1
g = (add(n,i) for i in g) 这里的代码因为跑过了 就不执行
n = 10
g = (add(n,i) for i in (add(n,i) for i in test()))
所以
g = (add(10,i) for i in (add(10,i) for i in [0,1,2,3]))
g = (add(10,i) for i in (10,11,12,13)
g = (20,21,22,23)
'''
print(list(g)) #[20, 21, 22, 23] 当没有调用的时候上面的代码都不会执行

最新文章

  1. [LeetCode] Best Meeting Point 最佳开会地点
  2. 利用PHP的register_shutdown_function来记录PHP的输出日志,模拟析构函数
  3. OLAT &amp; OLTP
  4. Flash Socket简单调试工具
  5. JAVA 数组排序
  6. Python之路3Day
  7. C# 将字符串转为&amp;#2345;这种的 html实体编码
  8. 成功破解邻居的Wifi密码
  9. [Redis]处理定时任务的2种思路
  10. Android开发专业名词及工具概述
  11. MySQL占用IO过高解决方案【转】
  12. C#基础篇六飞行棋
  13. 《Linux内核分析》第二周学习小结 操作系统是如何工作的?
  14. JS的prototype和__proto__、constructor
  15. Spring在Web容器启动时执行初始化方法
  16. 为什么要用Zero-Copy机制?
  17. 带你走进脚本世界,ijkplayer之【init-ios.sh】脚本分析
  18. 在DOS命令行窗口中显示系统环境环境变量
  19. 什么是AOP和OOP,IOC和DI有什么不同?
  20. Spring:org.springframework.beans.factory.CannotLoadBeanClassException: Cannot find class

热门文章

  1. Activiti task claim concurrent
  2. linux系统上传下载命令rz和sz的教程
  3. [报错处理]Python Requests - No connection adapters
  4. mybatis自动生成后无法获取主键id问题
  5. 【VS开发】VS2015没修改源文件也导致重新编译的解决办法
  6. SpringBoot+Mybatis+MySql 自动生成代码 自动分页
  7. 谈谈php里的IOC控制反转,DI依赖注入(转)
  8. 《PHP - 信号/基本操作/配置》
  9. Connection to api@localhost failed. [08001] Could not create connection to d
  10. openstack-nova源码之创建虚拟机