使用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] 当没有调用的时候上面的代码都不会执行

Python学习日记(十) 生成器和迭代器的更多相关文章

  1. Python学习笔记之生成器、迭代器和装饰器

    这篇文章主要介绍 Python 中几个常用的高级特性,用好这几个特性可以让自己的代码更加 Pythonnic 哦 1.生成器 什么是生成器呢?简单来说,在 Python 中一边循环一边计算的机制称为 ...

  2. Python学习之旅—生成器与迭代器案例剖析

    前言 前面一篇博客笔者带大家详细探讨了生成器与迭代器的本质,本次我们将实际分析一个具体案例来加深对生成器与迭代器相关知识点的理解. 本次的案例是一个文件过滤操作,所做的主要操作就是过滤出一个目录下的文 ...

  3. python学习日记(生成器函数进阶)

    迭代器和生成器的概念 迭代器 对于list.string.tuple.dict等这些容器对象,使用for循环遍历是很方便的.在后台for语句对容器对象调用iter()函数.iter()是python内 ...

  4. python 学习2:生成器,迭代器,装饰器

    1.生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万  个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那 ...

  5. Python学习日记(十八) 序列化模块

    什么是序列? 就是每一个元素被有序的排成一列 什么是序列化? 就是将原本的列表.字典等内容转化成字符串的过程 什么时候会用到序列化? 数据存储(把数据放在文件.数据库),网络传输等 序列化的目的 1. ...

  6. Python学习日记(十六) time模块和random模块

    time模块 python表示时间的三种方式:时间戳.元祖(struct_time).格式化时间字符串 三种格式之间的转换: 1.时间戳 就是从1970年1月1日0点0分0秒开始按秒计算的偏移量,时间 ...

  7. Python学习日记(十四) 正则表达式和re模块

    正则表达式: 它是字符串的一种匹配模式,用来处理字符串,可以极大地减轻处理一些复杂字符串的代码量 字符组:它是在同一位置可能出现的各种字符组成了一个字符组,用[]表示,但是它的结果只能是一个数字或者一 ...

  8. Python学习日记(十二) 匿名函数

    匿名函数: 未解决一些简单的需求而设计的函数 语法: func = lambda x : x**2 func:函数名 lambda:类似def的关键字 x:参数 x**2:返回值表达式 适用内置函数: ...

  9. Python学习日记(十九) 模块导入

    模块导入 当文件夹中有这样一个自定义的command模块 在它的内部写下下列代码: print('这个py文件被调用!') def fuc(): print('这个函数被调用!') 然后我们在comm ...

随机推荐

  1. 2019年10~11月-NLP工程师求职记录

    求职目标:NLP工程师 为什么想换工作? 除了技术相关书籍,我没读过太多其他类型的书,其中有一本内容短但是对我影响特别大的书--<谁动了我的奶酪>.出门问问是我毕业后的第一份工作,无论是工 ...

  2. 百度开源上传组件webuploader 可上传多文件并带有进度条

    //上传多文件 function UploadMultiFile() { var uploader = WebUploader.create({ // 选完文件后,是否自动上传. auto: true ...

  3. db2常用操作命令

    1. 打开命令行窗口 #db2cmd 2. 打开控制中心 # db2cmd db2cc 3. 打开命令编辑器 db2cmd db2ce =====操作数据库命令===== 4. 启动数据库实例 #db ...

  4. 学习使用Lombok生成代码

    一.介绍 Lombok官网:https://projectlombok.org/ Lombok的功能简单一点说,就是可以帮我们生成一些代码,这些代码并不是在源码(source code)体现出来的,而 ...

  5. DevOps - DevOps精要 - 变革

    特别说明 本文是已读书籍的学习笔记和内容摘要,原文内容有少部分改动,并添加一些相关信息,但总体不影响原文表达. <DevOps入门与实践> :本书结合实例详细介绍了在开发现场引入DevOp ...

  6. Kubernetes 集群日志管理 Elasticsearch + fluentd(二十)

    目录 一.安装部署 Kubernetes 开发了一个 Elasticsearch 附加组件来实现集群的日志管理.这是一个 Elasticsearch.Fluentd 和 Kibana 的组合.Elas ...

  7. 最新 识装java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿. 识装等10家互联网公司的校招Offer,因为某些自身原因最终选择了 识装.6.7月主要是做系统复习.项目复盘.LeetCo ...

  8. Redis 主从配置密码以及哨兵

    目录: Redis 主从介绍 哨兵机制 Redis 主从配置 环境 安装 启动服务 检查主从状态 测试数据同步 默认是读写分离的 Redis Sentinel 配置 主Redis宕机测试 配置多个哨兵 ...

  9. 【python小记】访问mysql数据库

    题记: 最近因为工作需要,学习了python,瞬间对这个轻松快捷的语给吸引了,以前只知道js脚本是写网页的,没有想到python这个脚本语言的应用范围可以这么广泛,现在做一些简单或稍微复杂的操作,基本 ...

  10. Redhat7.6Linux版本下,在Oracle VM VirtualBox下hostonly下IP地址配置

    安装配置Linux的Redhat7.6教程见:https://www.cnblogs.com/xuzhaoyang/p/11264563.html 然后,配置完之后,我们开始配置IP地址,配置IP地址 ...