python之推导式 生成器 生成器函数 递归函数

推导式

通过一行循环判断遍历出一些列数据的方法叫做推导式

语法:
val for val in iterable

1.推导式基本语法

lst = []
for i in range(1,51):
    lst.append(i)
print(lst)

改写推导式

lst = [  i for i in range(1,51)  ]
print(lst)

小练习

1.[1,2,3,4,5] => [2,4,6,8,10]
lst = [ i*2 for i in range(1,6) ]
print(lst)

2.带有判断条件的推导式

注意点:for后面紧跟的判断条件只能是单项分支.

[1,2,3,4,5,6,7,8,9,10] => [1,3,5,7,9 … ]

lst = [1,2,3,4,5,6,7,8,9,10]
lst_new = []
for i in lst:
    if i % 2 == 1:
        lst_new.append(i)
print(lst_new)

改写推导式

lst = [ i for i in lst if i % 2 == 1 ]
print(lst)

3.多循环推导式 # 谁♡♢♤♠谁

lst1 = ["孙杰龙","陈露","曹静怡"]
lst2 = ["王志国","邓鹏","合理"]
lst_new = []
for i in lst1:
    for j in lst2:
        lst_new.append(i+"♡♢♤♠"+j)
print(lst_new)

改写推导式

lst = [ i+"♡♢♤♠"+j for i in lst1 for j in lst2 ]
print(lst

4.带有判断条件的多循环推导式

lst_new = []
for i in lst1:
    for j in lst2:
        if lst1.index(i) == lst2.index(j):
            lst_new.append(i+"♡♢♤♠"+j)
print(lst_new)

改写推导式

lst = [i+"♡♢♤♠"+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]
print(lst)

集合推导式

案例:
满足年龄在18到21,存款大于等于5000 小于等于5500的人,
开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)
把开卡的种类统计出来

lst = [
    {"name":"赵沈阳","age":18,"money":3000},
    {"name":"赵万里","age":19,"money":5200},
    {"name":"赵蜂拥","age":20,"money":100000},
    {"name":"赵世超","age":21,"money":1000},
    {"name":"王志国","age":18,"money":5500},
    {"name":"王永飞","age":99,"money":5500}
]
setvar = set()
for i in lst:
    print(i) # {'name': '赵沈阳', 'age': 18, 'money': 3000}
    if 18 "age"] and 5000 "money"] :
        res = "尊贵VIP卡老{}".format(i["name"][0])
    else:
        res = "抠脚大汉卡老{}".format(i["name"][0])
    # 添加到集合中
    setvar.add(res)
print(setvar)

{ 三元运算符 + 推导式 }

setvar = { "尊贵VIP卡老{}".format(i["name"][0]) if 18 "age"] and 5000 "money"] else "抠脚大汉卡老{}".format(i["name"][0]) for i in lst }
print(setvar)

字典推导式

一.enumerate

enumerate(iterable,[start=0])
功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
参数:
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
start: 可以选择开始的索引号(默认从0开始索引)
返回值:迭代器

基本语法

from collections import Iterator,Iterable
lst =["王文","吕洞宾","何仙姑","铁拐李","张国老","曹国舅","蓝采和","韩湘子"]
it = enumerate(lst)
it = enumerate(lst,start=100)
print(isinstance(it,Iterator))

next

print( next(it) )

for + next (推荐,数据较大时使用)

for i in range(3):
    print(next(it))

for

for i in it:
    print(i)

list 强转迭代器

print(list(it))

(1) 字典推导式 配合 enumerate 来实现

dic = {k:v for k,v in enumerate(lst,start=100)}
print(dic)
"""
(100, '王文')
(101, '吕洞宾')
(102, '何仙姑')
(103, '铁拐李')
(104, '张国老')
(105, '曹国舅')
(106, '蓝采和')
(107, '韩湘子')
"""

(2) 使用dict强转迭代器,瞬间得到字典

dic = dict( enumerate(lst,start=100) )
print(dic)

二.zip

特点:按照索引配对
zip(iterable, … …)
功能: 将多个iterable中的值,一个一个拿出来配对组成元组,通过迭代器返回
iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
返回: 迭代器

基本语法

lst1 = ["孙开启","王永飞","于朝志"]
lst2 = ["薛宇健","韩瑞晓","上朝气"]
lst3 = ["刘文博","历史园","张光旭"]

在索引下标同时存在时,才会进行配对,否则舍弃.

lst1 = ["孙开启","王永飞","于朝志"]
lst2 = ["薛宇健","韩瑞晓"]
lst3 = ["刘文博"]

it = zip(lst1,lst2,lst3)
print(list(it))

(1) 字典推导式 配合 zip 来实现

lst_key = ["ww","axd","yyt"]
lst_val = ["王维","安晓东","杨元涛"]

('ww', '王维'), ('axd', '安晓东'), ('yyt', '杨元涛')
dic = {k:v   for k,v in zip(lst_key , lst_val) }
print(dic)

(2) 使用dict强转迭代器,瞬间得到字典

dic = dict( zip(lst_key , lst_val) )
print(dic)

生成器

生成器本质是迭代器,允许自定义逻辑的迭代器

迭代器和生成器区别:

迭代器本身是系统内置的.重写不了.

而生成器是用户自定义的,可以重写迭代逻辑

生成器可以用两种方式创建:
(1)生成器表达式 (里面是推导式,外面用圆括号)
(2)生成器函数 (用def定义,里面含有yield)

(1) 生成器表达式 (里面是推导式,外面用圆括号)

gen = ( i for i in range(10) )
print(gen)

判断类型

from collections import Iterator,Iterable
print(isinstance(gen,Iterator))

1.next 调用生成器

print(next(gen))
print(next(gen))

2.for + next 调用生成器

for i in range(3):
    print(next(gen))

3.for 调用生成器所有数据

for i in gen:
    print(i)

4.list强转生成器,瞬间得到所有数据

gen = ( i for i in range(10) )
print(list(gen))

print(next(gen)) error  # StopIteration

生成器函数

yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走,而return直接终止函数,每次重头调用.

yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

(1) 基本语法

def mygen():
    print("111")
    yield 1

    print("222")
    yield 2

    print("333")
    yield 3

初始化生成器函数  => 返回生成器对象 => 简称生成器
gen = mygen()

第一次调用
res = next(gen)
print(res)
第二次调用
res = next(gen)
print(res)
第三次调用
res = next(gen)
print(res)
第四次调用
"""
StopIteration error
res = next(gen)
print(res)
"""
"""
第一次调用
print("111")  yield 1 保存当前第13行代码的状态,把1返回,并且等待下一次调用
第二次调用
从上一次保存的位置13行往下走, print("222") yield 2 保存当前第16行代码的状态,把2返回,并且等待下一次调用
第三次调用
从上一次保存的位置16行往下走, print("333") yield 3 保存当前第19行代码的状态,把3返回,并且等待下一次调用
第四次调用
因为没

(2) 优化生成器代码

生成器应用的场景是在大数据的范围中使用,切记不可直接用for遍历所有,可能无法短时间内获取所有数据

def mygen():
    for i in range(1,101):
        yield i
初始化生成器函数 => 生成器
gen = mygen()
print("")
for i in range(30):
    num = next(gen)
    print("我的球衣号码是{}".format(num))

print("")
for i in range(40):
    num = next(gen)
    print("我的球衣号码是{}".format(num))

(3) send的使用方式 (给上一个yield发送数据)

next和send区别:
next 只能取值
send 不但能取值,还能发送值
send注意点:
第一个 send 不能给 yield 传值 默认只能写None
最后一个yield 接受不到send的发送值

def mygen():
    print("start")

    res = yield "内部1"
    print(res,"")

    res = yield "内部2"
    print(res,"")

    res = yield "内部3"
    print(res,"")

    print("end")

初始化生成器函数 => 生成器
gen = mygen()
第一次调用生成器
"""
第一次调用生成器时,因为没有遇到yield保存的代码位置,
无法发送数据,默认第一次只能发送None
"""
res = gen.send(None)
print(res,"")

第二次调用生成器
res = gen.send("100")
print(res,"")

第三次调用生成器
res = gen.send("200")
print(res,"")

第四次调用生成器
"""
error
res = gen.send("300")
print(res,"")
"""
"""
使用send调用生成器,第一次发送时必须是None,因为还没有遇到yield保存的代码位置
res = gen.send(None)  走到mygen生成器函数中
print("start")
res = yield "内部1"  执行第80行 ,保存退出,记录当前代码位置,将 "内部1" 返回
在98行接受数据  res = "内部1"  print(内部1,"")

第二次调用生成器
res = gen.send("100") 把100这个数据发送给上一次代码保存的位置80行进行接受. => 导致 80行 res = 100
打印81行  print(100 ,"")
执行83行  res = yield "内部2"  保存退出,记录当前代码位置,将 "内部2" 返回
执行102行 res = gen.send("100") => "内部2" print("内部2","")

....

依次类推 ...

到第四次调用时, 因为没有更多的yield 返回数据,gen.send(300)无法接受到返回值,所以出现停止迭代 StopIteration的报错,程序终止;
"""

(4) yield from 的使用

将一个可迭代对象变成一个迭代器返回

def mygen():
    lst = ["张磊","李亚峰","刘一峰","王同培"]
    yield from lst

初始化生成器函数
gen = mygen()
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen))
print(next(gen)) # StopIteration

(5) 斐波那契数列

“””使用生成器分段获取所有内容,而不是一股脑的把所有数据全部打印”””
“””1 1 2 3 5 8 13 21 34 …. “””

def mygen(maxval):
    a,b = 0,1
    i = 0
    while i < maxval:
        # print(b)
        yield b
        a,b = b,a+b
        i += 1
mygen(10)
gen = mygen(10)

第一次获取
for i in range(3):
    print(next(gen))

第二次获取
for i in range(5):
    print(next(gen))

递归函数

递归函数 : 自己调用自己的函数 , 叫做递归函数
递 : 去
归 : 回
一去一回叫做递归

def digui(n):
    print(n,"")
    if n > 0:
        digui(n-1)
    print(n,"")

digui(5)

"""
去的过程
n = 5 print(5,"")  if 5 > 0:   digui(5-1) =>  digui(4) 代码阻塞在第12行
n = 4 print(4,"")  if 4 > 0:   digui(4-1) =>  digui(3) 代码阻塞在第12行
n = 3 print(3,"")  if 3 > 0:   digui(3-1) =>  digui(2) 代码阻塞在第12行
n = 2 print(2,"")  if 2 > 0:   digui(2-1) =>  digui(1) 代码阻塞在第12行
n = 1 print(1,"")  if 1 > 0:   digui(1-1) =>  digui(0) 代码阻塞在第12行
n = 0 print(0,"")  if 0 > 0: 不成立 print(0,"") 到此最后一层函数空间彻底执行完毕

回的过程
回到上一层函数空间  n = 1 代码在第12行的位置,继续往下执行  print(1,"")
回到上一层函数空间  n = 2 代码在第12行的位置,继续往下执行  print(2,"")
回到上一层函数空间  n = 3 代码在第12行的位置,继续往下执行  print(3,"")
回到上一层函数空间  n = 4 代码在第12行的位置,继续往下执行  print(4,"")
回到上一层函数空间  n = 5 代码在第12行的位置,继续往下执行  print(5,"")

到此递归函数执行结束..

打印 543210012345
"""

"""
每次调用函数时,都要单独在内存当中开辟空间,叫做栈帧空间,以运行函数中的代码

递归总结:
    (1)递归实际上是不停的开辟栈帧空间和释放栈帧空间的过程,开辟就是去的过程,释放就是回的过程
    (2)递归什么时候触发归的过程:
        1.当最后一层栈帧空间执行结束的时候,触发归的过程.

        2.当遇到return返回值的时候终止当前函数,触发归的过程.

    (3)递归不能无限的去开辟空间,可能造成内存溢出,蓝屏死机的情况,所以一定要给予跳出的条件(如果递归的层数太大,不推荐使用)
    (4)开辟的一个个栈帧空间,数据是彼此独立不共享的.

"""

python之推导式 生成器 生成器函数 递归函数

递归原理图:

python之推导式 生成器 生成器函数 递归函数

递归不能不限开辟空间

官方说法最大默认是1000层

def deepfunc():
    deepfunc()
deepfunc()

1.使用递归实现任意数n的阶乘

普通实现

5! =5 *4*3*2*1
n = 5
total = 1
for i in range(n,0,-1):
    total *= i
print(total) # 120

递归实现

def jiecheng(n):
    if n :
        return 1
    return jiecheng(n-1) * n

print(jiecheng(2))
jiecheng(1) => 1
jiecheng(2) => jiecheng(1) * 2 => 1 * 2
jiecheng(3) => jiecheng(2) * 3 => 1 * 2 * 3
jiecheng(4) => jiecheng(3) * 4 => 1 * 2 * 3 * 4
jiecheng(5) => jiecheng(4) * 5 => 1 * 2 * 3 * 4 * 5
print(jiecheng(5))
"""
代码解析:
去的过程:
n = 5 return jiecheng(n-1) * n => jiecheng(4) * 5
n = 4 return jiecheng(n-1) * n => jiecheng(3) * 4
n = 3 return jiecheng(n-1) * n => jiecheng(2) * 3
n = 2 return jiecheng(n-1) * n => jiecheng(1) * 2
n = 1 return 1

回的过程:
n = 2 return jiecheng(1) * 2 => 1 * 2
n = 3 return jiecheng(2) * 3 => 1 * 2 * 3
n = 4 return jiecheng(3) * 4 => 1 * 2 * 3 * 4
n = 5 return jiecheng(4) * 5 => 1 * 2 * 3 * 4 * 5

到此程序结束:
返回  1 * 2 * 3 * 4 * 5
"""

2. 使用尾递归来实现任意数的阶乘

return 在哪调用,在哪返回
自己调用自己,且返回时非运算表达式,只是函数本身

特点:
尾递归只开辟一个空间,不会无限的开辟,在一个空间里面去计算最后的结果进行返回,比较节省空间,有的解释器支持尾递归的调用特点
但是cpython解释器目前不支持
写法:
所有运算的值都在函数的参数中计算完毕,最后返回运算的参数;

def jiecheng(n,endval):
    if n :
        return endval
    return jiecheng(n-1 , n * endval)
res = jiecheng(5,1) # 5*4*3*2*1
print(res)

"""
代码解析:
去的过程
n = 5 ,endval = 1 return jiecheng(n-1 , n * endval) => jiecheng(4,5*1) => 5*1*4*3*2
n = 4 ,endval = 5*1 return jiecheng(n-1 , n * endval) => jiecheng(3,5*1*4) => 5*1*4*3*2
n = 3 ,endval = 5*1*4 return jiecheng(n-1 , n * endval) => jiecheng(2,5*1*4*3) => 5*1*4*3*2
n = 2 ,endval = 5*1*4*3 return jiecheng(n-1 , n * endval) => jiecheng(1,5*1*4*3*2) => 5*1*4*3*2
n = 1 ,endval = 5*1*4*3*2   if n

图片解析

python之推导式 生成器 生成器函数 递归函数

优化代码1

def jiecheng(n,endval=1):
    if n :
        return endval
    return jiecheng(n-1 , n * endval)
res = jiecheng(5,100) # 5*4*3*2*1
print(res,"")

优化代码2 [把尾递归需要的参数值隐藏起来,避免篡改.]

def outer(n):
    def jiecheng(n,endval=1):
        if n :
            return endval
        return jiecheng(n-1 , n * endval)
    return jiecheng(n,1)# 120
print(outer(5))

优化代码3(扩展)
闭包实现

def outer(n):
    endval = 1
    def jiecheng(n):
        nonlocal endval
        if n :
            return endval
        endval *= n
        return jiecheng(n-1)
    return jiecheng
func = outer(5)
print(func(5),"")

3.使用递归来完成斐波那契数列

1 1 2 3 5 8 13 21 34 …

def feib(n):
    if n == 1 or n == 2:
        return 1

    # 上一个结果 + 上上个结果
    return feib(n-1) + feib(n-2)
print(feib(5))
"""
代码解析:
n = 5               feib(5) => 3 + 2 => return 5
        feib(4)        +         feib(3)
    feib(3)+feib(2)          feib(2)+feib(1) => 1 + 1 => 2
feib(2)+feib(1)+feib(2) => 1 + 1 + 1 => 3
"""

Original: https://www.cnblogs.com/shuaiyao666/p/15923861.html
Author: 小帅同学啊
Title: python之推导式 生成器 生成器函数 递归函数

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/814884/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球