python 生成器和递归
生成器
1.定义
- 问题:python会把对象放到内存中,我们每次定义变量、列表等都会在内存中占用对应的地址块,所以当内存容量一定时,列表的容量会受到内存的限制,而且假如我们创建了一个包含200万个元素的列表,不仅会占用很大的地址空间,如果我们仅仅需要访问前面的几个元素,那么会造成后面的元素占用的空间都浪费了。基于这个问题,生成器就可以很好的解决。
- 解决:生成器可以根据特定的算法,生成一个可迭代的对象,当我们调用此对象时,可以在循环过程中不断推算后续的元素,调用终止之后则不再循环,而后面的元素也就不在创建,这样很好的解决了上面的问题
- 定义:生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。 生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
- 生成器的特点: 生成器是一个函数,而且函数的参数都会保留。 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
2.创建
在函数中,如果使用了关键字yield时,此函数就是一个生成器,他的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是一个结果值,如果需要得道结果值,需要调用next()函数
如下:
#定义一个生成器func
def func():
print(111) #使用print打印每次循环的结果,便于查看
yield 1
print(222)
yield 2
print(333)
yield 3 res = func()
下面开始进行循环
方法1:使用for循环
for i in res:
print(i) 输出结果:
111 #生成器第一次pring
1 #yield返回的对象值
222 #生成器第二次pring
2 #yield返回的对象值
333 #生成器第三次pring
3 #yield返回的对象值
方法2:使用next()迭代
print("".center(10,'*'))
r1 = res.__next__() #进入函数找到yield,并去到yield后面的数据
print(r1) print("".center(10,'*'))
r2 = res.__next__() #进入函数找到yield,并去到yield后面的数据
print(r2) print("".center(10,'*'))
r3 = res.__next__() #进入函数找到yield,并去到yield后面的数据
print(r3) 输出结果:
****1*****
111
1
****2*****
222
2
****3*****
333
3
PS:for循环会自动调用next()方法,每当调用一次迭代器的next函数,生成器函数运行到yield之处,返回yield后面的值且在这个地方暂停,所有的状态都会被保持住,直到下次next函数被调用,或者碰到异常循环退出,所以如果一个生成器中一个yield被迭代之后,下次会读取下一个yield,所以for循环和next函数不能混用
- 生成器应用实例:排列和组合
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#pyversion:python3.5
#owner:fuzj #组合生成器
def perm(items, n = None):
if n is None:
n = len(items)
for i in range(len(items)):
v = items[i:i+1] #使用字符串分片,取其中的元素
if n==1: #如果是第一次循环,则打印第一个字符和第二个字符
yield v
else:
rest = items[:i] + items[i+1:] #i+1表示接着上次运行的状态i的值进行切片,取后面的值字符
for p in perm(rest, n-1): #递归调用本生成器,进行循环,此就是之前描述的特定规则
yield v + p
#排列生成器
def comb(items, n = None):
if n is None:
n = len(items)
else:
for i in range(len(items)):
v = items[i:i+1] #使用字符串分片,取其中的元素
if 1 == n: #第一次循环,则打印第一个和第二个字符
yield v
else:
rest = items[i+1:]
for c in comb(rest, n-1): #递归调用本生成器,进行循环,此就是之前描述的特定规则
yield v + c
p = perm('abcd',2)
c = comb('abcd',2)
print('组合'.center(10,"="))
for i in p:
print(i)
print('排列'.center(10,"="))
for i in c:
print(i)
输出效果: ====组合====
ab
ac
ad
ba
bc
bd
ca
cb
cd
da
db
dc
====排列====
ab
ac
ad
bc
bd
cd
递归
递归的理解,可以从一个需求中进行慢慢剖析
- 需求:计算1*2*3*....*1000的值
这是一个简单计算叠乘的需求,如果没接触递归之前,可以使用函数来实现
def func(arg):
res = arg
for i in range(1,arg):
res *= 1
return res
这个函数通过循环arg以内的数,再依次相乘最终返回结果,如果使用递归的方法,将更简单
def fun(arg):
if arg == 1:
return arg
return arg * fun(arg -1)
通过此函数发现,函数最终return的是函数本身的表达式,如果计算5以内的阶乘,他的运行如下:
1)fun(5)调用函数fun()函数,此时arg = 5,5>1,所以会return 5 * fun(4)
2)fun(4)会调用fun()函数,此时arg=4,4>1,所以会return 4 * fun(3)
3)fun(3)会调用fun()函数,此时arg=3,3>1,所以会return 3 * fun(2)
4)fun(2)会调用fun()函数,此时arg=2,2>1,所以会return 2 * fun(1)
5)fun(1)会调用fun()函数,此时arg=1,1=1,所以会return 1
6)当fun(1)将值返回给fun(2)之后,此时fun(2)=fun(1)*2=2,继续往上返回给fun(3)
7)当fun(2)将值返回给fun(3)之后,此时fun(3)=fun(2)*3=6,继续往上返回给fun(4)
8)当fun(3)将值返回给fun(4)之后,此时fun(4)=fun(3)*4=24,继续往上返回给fun(5)
9)当fun(4)将值返回给fun(5)之后,此时fun(5)=fun(4)*5=120,最终得出结果特点
创建递归的条件
1.一个基线条件:递归终止的条件,需递归开始的时候进行判断处理。
2.一系列的规则:使对递归函数的每次调用都趋进于直至达到这个基线条件
递归可以提高代码的可读性,但是运行效率较低。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。
python 生成器和递归的更多相关文章
- python生成器,递归调用
生成器 什么是生成器:只要在函数体内出现yield关键字,那么再执行函数就不会执行函数代码,会得到一个结果,该结果就是生成器 生成器就是迭代器 yield的功能 yield为我们提供了一种自定义迭代器 ...
- Python入门之三元表达式\列表推导式\生成器表达式\递归匿名函数\内置函数
本章目录: 一.三元表达式.列表推导式.生成器表达式 二.递归调用和二分法 三.匿名函数 四.内置函数 ================================================ ...
- Python实现JSON生成器和递归下降解释器
Python实现JSON生成器和递归下降解释器 github地址:https://github.com/EStormLynn/Python-JSON-Parser 目标 从零开始写一个JSON的解析器 ...
- python生成器原理剖析
python生成器原理剖析 函数的调用满足"后进先出"的原则,也就是说,最后被调用的函数应该第一个返回,函数的递归调用就是一个经典的例子.显然,内存中以"后进先出&quo ...
- python 内置&&递归
lambda 优点: 1:可以简单使用一个脚本来替代我们的函数 2:不用考虑命名的问题 3:简化代码的可读性,不用跳转到def了,省去这样的步骤 内置函数:bif filter:过滤器 map:映射 ...
- python——生成器
python——生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个 ...
- python手动设置递归调用深度
python超出递归深度时会出现异常: RuntimeError: maximum recursion depth exceeded python默认的递归深度是很有限的,大概是900当递归深度超过这 ...
- 使用Python语言理解递归
递归 一个函数在执行过程中一次或多次调用其本身便是递归,就像是俄罗斯套娃一样,一个娃娃里包含另一个娃娃. 递归其实是程序设计语言学习过程中很快就会接触到的东西,但有关递归的理解可能还会有一些遗漏,下面 ...
- 十四. Python基础(14)--递归
十四. Python基础(14)--递归 1 ● 递归(recursion) 概念: recursive functions-functions that call themselves either ...
随机推荐
- mac系统上使用压缩包版的mysql(非安装版)
mac本换了块固态硬盘,一切重新装过,mysql嫌官网下载太慢,直接百度 "mysql mac",第一个就是: 不料下载完后,发现这是一个压缩包版,并没有安装程序.网上搜索了一下, ...
- PhoneGap: Android 自定义组件
Hello Core Demo Plugin Development(组件部署): http://docs.phonegap.com/en/2.0.0/guide_plugin-development ...
- 我的 GitHub 100 连击
终于达成 gayhub 的第一个100连击了,感觉自己整个人颜色都不一样了,完全蜕变了. PS: GitHub 汉化插件 52cik/github-hans 感兴趣的赶紧 get 起来吧. 遇到瓶颈 ...
- ModernUI教程:主题资源引用
已经完成的主题资源列表 提示:请关注Modern UI的开发工作,资源文件可能在演进版本中新增和删除. 资源列表可以去访问原文,原文可复制,该表未改动原文. 查看目录
- 从Evernote迁移到Wiz
实在受不了evernote没完没了的弹出广告和让升级账号,我不过就是想安安静静的记个笔记,真不想看您的广告好吧.于是无奈这下,只能选择转换到别的笔记工具阵营. 由于以前一直听说OneNote是仅次于E ...
- Apache CXF实现WebService发布和调用
第一种方法:不用导入cxf jars 服务端: 1. 新建Web工程 2.新建接口和实现类.测试类 目录结构图如下: 接口代码: package com.cxf.spring.service; imp ...
- 《TCP/IP详解卷1:协议》第1章 概述-读书笔记
章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP ...
- window php redis扩展下载地址
redis扩展下载 http://windows.php.net/downloads/pecl/snaps/redis/
- C# Task 用法
C# Task 的用法 其实Task跟线程池ThreadPool的功能类似,不过写起来更为简单,直观.代码更简洁了,使用Task来进行操作.可以跟线程一样可以轻松的对执行的方法进行控制. 顺便提一下, ...
- 理解CDN
一.CDN定义 CDN的全称是Content Delivery Network,即内容分发网络.其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快.更稳定.通过 ...