使用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. db2常用操作命令

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

  2. Spring cloud微服务安全实战-8-1课程总结

    总结 首先讲了api的安全.安全常见的风险.安全措施.然后我们把简单的api演化成一个这种微服务的架构. 首先讲了在网关上可以做哪些安全的措施.然后讲了如何搭建一个安全中心,也就是认证服务器,包括一些 ...

  3. PAT 甲级 1076 Forwards on Weibo (30分)(bfs较简单)

    1076 Forwards on Weibo (30分)   Weibo is known as the Chinese version of Twitter. One user on Weibo m ...

  4. Coder 健康 知识

  5. 什么是 Web server

    前端开发人员应该对 Web 开发中的基本概念有一些了解,请简述 什么是 Web 服务器 Web 服务器能做什么 首先我们来了解什么是服务器(server) 一般来说,server 有两重意思 有时候 ...

  6. HLSL Shader编程基础总结

    转自:https://blog.csdn.net/Blues1021/article/details/47093487 基本前提概念 Shader是一种映射到GPU硬件汇编语言上的高级语言,Shade ...

  7. 「中山纪中集训省选组D1T1」最大收益 贪心

    题目描述 给出\(N\)件单位时间任务,对于第\(i\)件任务,如果要完成该任务,需要占用\([S_i, T_i]\)间的某个时刻,且完成后会有\(V_i\)的收益.求最大收益. 澄清:一个时刻只能做 ...

  8. C++标准异常与自定义异常

    参见https://www.runoob.com/cplusplus/cpp-exceptions-handling.html C++ 标准的异常 C++ 提供了一系列标准的异常,定义在 中,我们可以 ...

  9. Word 自带公式使用方法技巧(11)

    1. 快捷命令 在Word中输入「Alt+=」,可以打开Word中自带公式编辑器.这个编辑器似乎没有什么特别,但其实 Word 2010 以后是支持 LaTeX 语法的.常用规则如下: 分号: a/b ...

  10. class——python编程从入门到实践

    创建和使用类 1. 创建Dog类 class Dog: """一次模拟小狗的简单尝试""" def __init__(self, name, ...