阅读目录

一.迭代器

1. 迭代的概念

#迭代器即迭代的工具(自定义的函数),那什么是迭代呢?
#迭代:指一个重复的过程,每次重复都可以称之为一次迭代,并且每一次重复的结果是下一个迭代的初始值(例如:罚写作业100遍)

while True: #只是单纯地重复,因而不是迭代
print('===>') l=[1,2,3]
count=0
while count < len(l): #迭代
print(l[count])
count+=1

2.为何要有迭代器? 什么是可迭代对象? 什么是迭代器对象?

#1、为何要有迭代器?
对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器 #2、什么是可迭代对象?
可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下
'hello'.__iter__
(1,2,3).__iter__
[1,2,3].__iter__
{'a':1}.__iter__
{'a','b'}.__iter__
open('a.txt').__iter__ #3、什么是迭代器对象?
可迭代对象执行obj.__iter__()得到的结果就是迭代器对象
而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象 文件类型是迭代器对象
open('a.txt').__iter__()
open('a.txt').__next__() #4、注意:
迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象

为何要有迭代器?什么是可迭代对象?什么是迭代器对象?

 3.迭代器对象的使用

dic={'a':1,'b':2,'c':3}
iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身
iter_dic.__iter__() is iter_dic #True print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
print(iter_dic.__next__()) #等同于next(iter_dic)
# print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志 #有了迭代器,我们就可以不依赖索引迭代取值了
iter_dic=dic.__iter__()
while 1:
try:
k=next(iter_dic)
print(dic[k])
except StopIteration:
break #这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环

迭代器对象的使用

4. for循环原理

#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
print(dic[k]) #for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环

5. 迭代器的优缺点

#优点:
- 提供一种统一的、不依赖于索引的迭代方式
- 惰性计算,节省内存
#缺点:
- 无法获取长度(只有在next完毕才知道到底有几个值)
- 一次性的,只能往后走,不能往前退

二. 生成器

  1. 什么是生成器

   生成器:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

   生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

#只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码
def func():
print('====>first')
yield 1
print('====>second')
yield 2
print('====>third')
yield 3
print('====>end')
g=func()
print(g) #<generator object func at 0x0000000002184360>

  2.生成器就是迭代器

g.__iter__
g.__next__
#所以生成器就是迭代器,因此可以这么取值
res=next(g)
print(res)

  3.生成器Generator总结:

    本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)

    特点:惰性运算,开发者自定义

  4.生成器函数

    一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。

import time
def generator_fun1():
a = 1
print('现在定义了a变量')
yield a
b = 2
print('现在又定义了b变量')
yield b g1 = generator_fun1()
print('g1 : ',g1) #打印g1可以发现g1就是一个生成器
print('-'*20) #我是华丽的分割线
print(next(g1))
time.sleep(1) #sleep一秒看清执行过程
print(next(g1))

  5.生成器有什么好处呢?

    1.延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。

# 假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
# 而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。 def produce():
"""生产衣服"""
for i in range(2000000):
yield "生产了第%s件衣服"%i product_g = produce()
print(product_g.__next__()) #要一件衣服
print(product_g.__next__()) #再要一件衣服
print(product_g.__next__()) #再要一件衣服
num = 0
for i in product_g: #要一批衣服,比如5件
print(i)
num +=1
if num == 5:
break #到这里我们找工厂拿了8件衣服,我一共让生产函数(也就是produce生成器函数)生产2000000件衣服。
#剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿

示例

  6.练习

#1、自定义函数模拟range(1,7,2)

#2、模拟管道,实现时时获取文件中最新内容
# 1、自定义函数模拟range(1,7,2)
def myRange(start,stop,step=1):
while start < stop:
yield start
start += step obj = myRange(1,7,2)
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj)) #StopIteration #2、模拟管道,实现时时获取文件中最新内容
import time
def tail(filename):
with open(filename,'r',encoding='utf-8')as f:
f.seek(0,2) #从文件末尾开始读取
while True:
line = f.readline()
if not line:
time.sleep(0.5)
continue
yield line obj = tail('a.txt')
for i in obj:
print(i)

代码示例

7.协程函数

  什么是协程:

  协程是一个无优先级的子程序调度组件,允许子程序在特点的地方挂起恢复。(类似于看电影时的暂停播放)

  线程包含于进程,协程包含于线程。只要内存足够,一个线程中可以有任意多个协程,但某一时刻只能有一个协程在运行,多个协程分享该线程分配到的计算机资源。

#yield关键字的另外一种使用形式:表达式形式的yield
def eater(name):
print('%s 准备开始吃饭啦' % name)
food_list=[]
while True:
food = yield food_list
print('%s 吃了 %s' % (name, food))
food_list.append(food) e=eater('钢蛋')
print(e.send(None)) #初始化,对于表达式形式的yield,在使用时,第一次必须传None,e.send(None)等同于next(e)
print(e.send('包子'))
print(e.send('韭菜馅包子'))
print(e.send('大蒜包子'))
e.close() #关闭
print(e.send('大麻花'))
#send 获取下一个值的效果和next基本一致
#只是在获取下一个值的时候,给上一yield的位置传递一个数据
#使用send的注意事项
# 第一次使用生成器的时候 是用send(None)或者 next进行初始化

 8.练习:

  1、编写装饰器,实现初始化协程函数的功能

def init(func):
def inner(*args,**kwargs):
res = func(*args,**kwargs)
next(res) #在装饰器中执行初始化方法
return res
return inner @init
def eater(name):
print('%s 准备开始吃饭啦' % name)
food_list=[]
while True:
food = yield food_list
print('%s 吃了 %s' % (name, food))
food_list.append(food) e=eater('钢蛋')
# e.send(None)
print(e.send('包子'))
print(e.send('韭菜馅包子'))
print(e.send('大蒜包子'))

装饰器实现初始化协程方法

 9. yield 关键字 总结

1、把函数做成迭代器
2、对比return,可以返回多次值,可以挂起/保存函数的运行状态

三. 列表推导式、生成器表达式

  1.列表推导式

#1、示例
egg_list=[]
for i in range(10):
egg_list.append('鸡蛋%s' %i) print(egg_list) #列表推导式1
egg_list = ['臭鸡蛋%s' %i for i in range(0,10) ]
print(egg_list) #列表推导式2
egg_list = ['臭鸡蛋%s' %i for i in range(0,10) if i>6]
print(egg_list) #2、语法
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
类似于
res=[]
for item1 in iterable1:
if condition1:
for item2 in iterable2:
if condition2
...
for itemN in iterableN:
if conditionN:
res.append(expression) #3、优点:方便,改变了编程习惯,可称之为声明式编程

  2.生成器表达式

#生成器表达式
#1、把列表推导式的[]换成()就是生成器表达式 #2、示例:生一筐鸡蛋变成给你一只老母鸡,用的时候就下蛋,这也是生成器的特性
chicken=('鸡蛋%s' %i for i in range(5)) print(chicken) # generator object <genexpr> at 0x10143f200> print(next(chicken)) #'鸡蛋0' print(list(chicken)) #因chicken可迭代,因而可以转成列表 ['鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4',] #3、优点:省内存,一次只产生一个值在内存中

  总结:

    1.把列表解析的[]换成()得到的就是生成器表达式

    2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

 4.声明式编程练习题

1、将names=['egon','alex_sb','wupeiqi','yuanhao']中的名字全部变大写

2、将names=['egon','alex_sb','wupeiqi','yuanhao']中以sb结尾的名字过滤掉,然后保存剩下的名字长度

3、求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)

4、求文件a.txt中总共包含的字符个数?思考为何在第一次之后的n次sum求和得到的结果为0?(需要使用sum函数)

5、思考题
with open('a.txt') as f:
g=(len(line) for line in f)
print(sum(g)) #为何报错?
# 1、将names=['egon','alex_sb','wupeiqi','yuanhao']中的名字全部变大写
names=['egon','alex_sb','wupeiqi','yuanhao']
names = [name.upper() for name in names]
print([name.upper() for name in names]) # 2、将names=['egon','alex_sb','wupeiqi','yuanhao']中以sb结尾的名字过滤掉,然后保存剩下的名字长度
names=['egon','alex_sb','wupeiqi','yuanhao']
names = [len(name) for name in names if not name.endswith("sb") ]
print(names)
# 3、求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)
with open('a.txt','r',encoding='utf-8')as f:
print(max(len(i) for i in f)) #最后有一个换行符 # 4、求文件a.txt中总共包含的字符个数?思考为何在第一次之后的n次sum求和得到的结果为0?(需要使用sum函数)
with open('a.txt','r',encoding='utf-8') as f:
print(sum(len(i) for i in f))
print(sum(len(i) for i in f)) #原因读取文件的指针已经到文件的末尾了
# 5、思考题
with open('a.txt') as f:
g=(len(line) for line in f)
print(sum(g)) #为何报错?
#答: with open 在执行完文件操作后,会自动关闭掉此文件,所以再使用文件内容时会报错

代码示例

四.递归函数

  1. 递归调用的定义

#递归调用是函数嵌套调用的一种特殊形式,函数在调用时,直接或间接调用了自身,就是递归调用

  2.递归分为两个阶段:递推,回溯

#问年龄游戏
#图解。。。
# age(4) = age(3) + 2
# age(3) = age(2) + 2
# age(2) = age(1) + 2
# age(1) = 40 def age(n):
if n == 1:
return 40
else:
return age(n-1)+2 print(age(4))

3.递归的使用

#总结递归的使用:
. 必须有一个明确的结束条件 . 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 . 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,
  每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出) .递归默认调用的最大深度为 ---

 4.设置递归最大深度

#设置递归最大深度
#注意:实际上可以达到的深度 取决于计算机的性能了
import sys
sys.setrecursionlimit(10000) #递归最大深度 def func1(n):
print(">>>>>>",n)
n+=1
func1(n) func1(0)

  5.练习题 

  1.使用递归函数完成三级菜单

menu = {
'北京': {
'海淀': {
'五道口': {
'soho': {},
'网易': {},
'google': {}
},
'中关村': {
'爱奇艺': {},
'汽车之家': {},
'youku': {},
},
'上地': {
'百度': {},
},
},
'昌平': {
'沙河': {
'老男孩': {},
'北航': {},
},
'天通苑': {},
'回龙观': {},
},
'朝阳': {},
'东城': {},
},
'上海': {
'闵行': {
"人民广场": {
'炸鸡店': {}
}
},
'闸北': {
'火车战': {
'携程': {}
}
},
'浦东': {},
},
'山东': {},
}

menu

def threeLM(dic):
while True:
for k in dic:print(k) key = input('input>>').strip() if key == 'b' or key == 'q':return key elif key in dic.keys() and dic[key]:
ret = threeLM(dic[key])
if ret == 'q': return 'q' threeLM(menu)
#递归函数实现三级菜单

递归函数实现三级菜单

 五. 二分查找法

  想从一个按照从小到大排列的数字列表中找到指定的数字,遍历的效率太低,用二分法(算法的一种,算法是解决问题的方法)可以极大低缩小问题规模

  二分查找法 简单版
#二分查找法
l=[1,2,10,30,33,99,101,200,301,402] #从小到大排列的数字列表
count = 0 #
def search(num,l):
global count
count+=1
if l:
print(l) #查看列表的变化
mid = (len(l)-1)//2
if num > l[mid]:
l=l[mid+1:] # 取列表右边数据
elif num < l[mid]:
l =l[:mid] # 取列表左边数据
else:
print(l[mid])
return #通过return 终止递归
search(num,l) #递归循环调用
else:
print("没有找到指定数字") search(10,l)
print(count)

 二分查找法升级版  

#二分查找法 升级版
l=[1,2,10,30,33,99,101,200,301,402] def search(num,l,start=0,stop=len(l)-1):
if start <= stop:
mid=start+(stop-start)//2
print('start:[%s] stop:[%s] mid:[%s] mid_val:[%s]' %(start,stop,mid,l[mid]))
if num > l[mid]:
start=mid+1
elif num < l[mid]:
stop=mid-1
else:
print('find it',mid)
return
search(num,l,start,stop)
else: #如果stop > start则意味着列表实际上已经全部切完,即切为空
print('not exists')
return search(101,l)

六 练习 

#1.使用递归打印斐波那契数列(前两个数的和得到第三个数,如:0 1 1 2 3 4 7...)

#2.一个嵌套很多层的列表,如l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用递归取出所有的值
#1.使用递归打印斐波那契数列(前两个数的和得到第三个数,如:0 1 1 2 3 4 7...)

#非递归
def fib(n):
a,b=0,1
while a < n:
print(a,end=' ')
a,b=b,a+b
print() fib(10)
#递归
def fib(a,b,stop):
if a > stop:
return
print(a,end=' ')
fib(b,a+b,stop) fib(0,1,10) #2. 一个嵌套很多层的列表,如l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用递归取出所有的值 l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]] def get(seq):
for item in seq:
if type(item) is list:
get(item)
else:
print(item)
get(l)

代码示例

Python开发【第五篇】迭代器、生成器、递归函数、二分法的更多相关文章

  1. Python开发第五篇

    面向对象程序设计 面向过程编程:就是分析问题的解决步骤,按部就班的编写代码解决问题 函数式编程:就是把代码封装到函数中,然后在使用时调用封装好的函数 面向对象编程:把一类事物所共有的属性和行为提取出来 ...

  2. Python开发【第二篇】:初识Python

    Python开发[第二篇]:初识Python   Python简介 Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏 ...

  3. Python开发【第一篇】:目录

    本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! Python开发[第一篇]:目录 Python开发[第二篇]:初识Python ...

  4. Python开发【第一篇】:目录

    本系列博文包含Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习Python编程的朋友们提供一点帮助! .Python开发[第一篇]:目录 .Python开发[第二篇]:初始P ...

  5. Python开发【第一篇】基础题目二

    1 列表题 l1 = [11, 22, 33] l2 = [22, 33, 44] # a. 获取l1 中有,l2中没有的元素 for i in l1: if i not in l2: # b. 获取 ...

  6. Python开发【第一篇】Python基础之生成器和迭代器

    生成器和迭代器 1.生成器 一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator):如果函数中包含yield语法,那这个函数就会变成生成器: def func(): yield 1 ...

  7. Python开发【第一篇】:初识Python

    初识python 一.python简介 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解 ...

  8. 深入理解python中可迭代对象,迭代器,生成器

    英文原文出处:Iterables vs. Iterators vs. Generators 在python学习中,通常会陷入对以下几个相关概念之间的确切差异的困惑中: a container(容器) ...

  9. python开发第四篇:函数(1)

    函数 阅读目录 一 函数知识体系 二 函数基础 三 函数对象.函数嵌套.名称空间与作用域.装饰器 四 迭代器.生成器.面向过程编程 五 三元表达式.列表推导式.生成器表达式.递归.匿名函数.内置函数 ...

  10. 跟着老男孩教育学Python开发【第一篇】:初识Python

    Python简介 Python前世今生 Python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解 ...

随机推荐

  1. 关于VC++6.0与WIN10系统不兼容的解决办法

    记得第一次接触C语言,用的第一个编译器就是VC++6.0.当时自己的是Win10系统,第一次安装就打不开,后来网上一查说是系统兼容性的问题.今天室友突然想安装VC++6.0,也遇到了兼容的问题,我就帮 ...

  2. C++多线程,互斥,同步

    同步和互斥 当有多个线程的时候,经常需要去同步这些线程以访问同一个数据或资源.例如,假设有一个程序,其中一个线程用于把文件读到内存,而另一个线程用于统计文件中的字符数.当然,在把整个文件调入内存之前, ...

  3. Openstack入门篇(十三)之云主机创建

    1.知识回顾与端口总结 service 功能 MySQL 为各个服务提供数据存储 RabbitMQ 为各个服务之间通信提供交通枢纽 Keystone 为各个服务器之间通信提供认证和服务注册 Glanc ...

  4. 180804-Spring之动态注册bean

    Spring之动态注册bean 什么场景下,需要主动向Spring容器注册bean呢? 如我之前做个的一个支持扫表的基础平台,使用者只需要添加基础配置 + Groovy任务,就可以丢到这个平台上面来运 ...

  5. X509证书申请以及PKCS#10 详解

    一.证书颁发 1.单证书的签发 1) 用户填写信息注册(或者由RA的业务操作员注册用户). 2) 用户信息传递到RA. 3) RA审核通过. 4) 用户请求发证. 5) RA审核通过. 6) 用户签发 ...

  6. 【LeetCode算法题库】Day5:Roman to Integer & Longest Common Prefix & 3Sum

    [Q13] Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. Symbol Valu ...

  7. 浅谈ajax同步、异步的问题

    最近实习的时候看到过firefox的同步.异步的警告,想着概念不是那么清楚,于是整理了一下ajax同步异步方面的知识.我是小白,做个笔记. 首先就是概念问题,ajax根据async进行区分同步和异步过 ...

  8. Java创建对象的动作分析

    一.Java创建对象时将对象存放到内存的堆中. 创建对象时先执行类成员的初始化,然后才会调用构造函数初始化对象, package com.test.createsort; public class C ...

  9. Docker持久化存储与数据共享

    一.Docker持久化数据的方案 基于本地文件系统的Volume:可以在执行docker create或docker run时,通过-v参数将主机的目录作为容器的数据卷.这部分功能便是基于本地文件系统 ...

  10. 小程序与WebRTC联姻能擦出怎样的火花?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯视频云终端团队发表于云+社区专栏 腾讯视频云终端技术总监,rexchang(常青), 2008 年毕业加入腾讯,一直从事客户端研发 ...