迭代器与生成器,装饰器,推导式

* 递归 * 总结 ##迭代器

可迭代对象(iteration)

遵守可迭代对象的协议 具有__iter__()方法

print(dict.__iter__({‘i’:1}))

除去整型和布尔值剩下现已知都是
迭代器(iterator): 遵守迭代器的协议 具有__iter__()方法和__next__()方法
创建一个迭代器 == 可迭代对象.iter()
使用迭代器 == 迭代器.next()

迭代器:不能回退,惰性机制,一次性的

for循环的机制 两种方式

生成器

生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去。

1.
lst = [1,2,3,4,5]
count = 0
l = lst.__iter__()
while count < len(lst):
    print(l.__next__())
    count += 1
2.
lst = [1,2,3,4,5,67,7]
l = lst.__iter__()
while True:
try:   # 异常捕获
  print(l.__next__())
except StopIteration:
  break
s = '123'.__iter__()
s1 = s.__iter__()
print(s1.__next__())
print(s.__next__())

怎么查看是迭代器还是可迭代对象:

from collections import Iterator,Iterable
print(isinstance([1,2,3],Iterable))   # 查看是否是可迭代的
print(isinstance('查看的内容',Iterator))   # 查看是否是迭代器

加上__.iter__()就是迭代器

生成器

定义

函数体中存在yield就是生成器,函数+()就产生 生成器
_next__ 和 yield 要一一对应, 最后的一个yield下边能写就是不运行

生成器是迭代器,具有迭代器的可迭代和使用next()函数的功能。记住:生成器是一种特殊的迭代器

三、为什么要使用生成器函数,而不是直接使用函数

1、通过列表生成式可以直接创建一个列表,但是受到内存的限制,可能创建一个很大的空间,但是实际情况中用不到那么多(在C语言中所谓的堆区,没释放)

2、生成器(generator)的定义就是根据列表元素可以动态的分配内存空间

3、在实际开发过程中,如果我们要读取一个十几G大的文件,如果是直接使用文件打开的方式,其实底层的全部加载在内存中,这样造成计算机内存消耗,造成计算机卡死的局面,如果我们使用生成器,把大文件做成文档碎片的方式,每次从中间读取一点出来,然后再释放内存,这样就不会对计算机造成卡死的局面。

def foo():
    print(1)
    n = yield 2
    print(n)
    print(3)
    yield 4
g = foo()
print(g) #<generator object foo at 0x0000026218165AF0>
print(g.__next__())
print(g.send(66))

结果:1 2 66 3 4
send() 发送 send() == next + 传值
send()传递给上一个yield的
最后的一个 yield 下边的可以写代码,但是执行不到
第一次启动这个生成器的时候 生成器.next 或 生成器.send(None)

生成器的好处

节省空间
可以for去执行这个生成器直接打印i就行,for的本身就是一直的__next__
yield from 调用的时候只能使用__next__()啊

推导式

1)列表推导 a=[结果 for I in 可迭代对象]

li = [i for i in range(10) if i>4] 

2)字典dic={k:v for k,v in 可迭代}

dic={'a':'b','c':'d'}
d={k:c for k,c in dic.items()}
    print(d)

3)集合s=set{结果 for I in 可迭代对象}

lst=['a','c']
lst1=['b','d']
d={lst[i]:lst1[i] for i in range(2)}
    print(d)

4)生成器s=(结果 for I in 可迭代对象) 长得像元祖

l=(i for i in range(100))
for i in range(10):
    print(l.__next__())

装饰器

1.本质就是闭包
开放封闭原则
扩展开发,修改源代码封闭,不能修改调用方式
在不改源代码的基础上添加功能
@装饰器的名字 在被装饰的函数正上方  独占一行
@语法糖 被装饰的函数名 = 装饰器的名字(被装饰的函数名)

3,python装饰器的应⽤场景装饰器的应⽤场景

1,引⼊⽇志

2,函数执⾏时间统计

3,执⾏函数前预备处理

4,执⾏函数后清理功能

5,权限校验等场景

6,缓存

7,事务处理

在 Flask 或 Django 框架中,用于路由函数或视图函数上,以实现权限控制、日志记录等功能。
在测试框架中,用于标记测试用例或测试函数,以设置断言、超时等条件。
在日志系统中,用于记录函数的入参和出参,以便调试和分析程序的行为。
在性能分析工具中,用于统计函数的执行时间或内存占用情况。
在缓存系统中,用于缓存函数的计算结果,以提高程序的执行效率

2.装饰器作用:

在不改变函数调用方式的基础上添加一些功能

3.functools.wraps的作用

保留原有函数的名称(消除装饰器带来的副作用)

简单写一个装饰器

import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time()-start)
        return re
    return inner
  
@timer     #==> func1 = timer(func1)
def func1(a,b):
    print('in func1')

@timer
def func2(a):
    print('in func2  and get a:%s'%(a))    #n func2  and get a:cccc 
    return 'func2 over'

func1('aaa','bbbb')   #in func1
print(func2('cccc'))   #i  func2 over

有参装饰器

内置函数

all()可迭代对象中都为真才是真
方法一:

size = "lg"
color = "blue"
price = 50
# bad practice
if size == "lg" and color == "blue" and price < 100:
    print("Yes, I want to but the product.")

方法一:size = "lg"
color = "blue"
price = 50

bad practice

if size == "lg" and color == "blue" and price < 100:
print("Yes, I want to but the product.")

方法二:

conditions = [
    size == "lg",
    color == "blue",
    price < 100,
]
if all(conditions):
    print("Yes, I want to but the product.")

Any()可迭代对象中有一个为真就是真
any用法同上

callable判断是否可调用
print(pow(2,3)) 求幂
print(pow(2,3,3)) 求幂后再取余
print(round(3.332324,3)) #四舍五入 第一个参数是浮点数  第二参数的要保留的小数位

1.lambda匿名函数

语法:lambda 参数:返回值
定义:lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数。

lambda函数有什么好处?

lambda函数比较轻便,即用即仍;
匿名函数,一般用来给filter,map这样的函数式编程服务;
作为回调函数,传递给某些应用,比如消息处理

匿名函数没有名字,怎么查看 函数.name
匿名函数的返回值只能是一个,不能是多个
匿名函数可不可以写到一行

print((lambda x,y:x+y)(3,6))  

print((lambda x:x)()) 调用的时候要传参

def func(n):
    return n**n
print(func(4))
  等同于下:
f = lambda x: x**x
print(f(4))

写上end='\n'和不写end是换行,end=''是两个连在一起

print('bjk','hjb',sep='   |') #sep默认是空格
print('mk','jjnk',end='')

repr显示数据原生
例:1)和函数组合使用
 定义一个列表,然后根据一元素的长度排序
lst = ['天龙八部','西游记','红楼梦','三国演义']
def func(s):
    return len(s)
print(sorted(lst,key=func))
 结果:
['西游记', '红楼梦', '天龙八部', '三国演义']
2)和lambda组合使用:
lst = ['天龙八部','西游记','红楼梦','三国演义']
print(sorted(lst,key=lambda s:len(s)))

2.sorted()

sorted :内置函数 排序
语法:sorted(iterable,key=None,reverse=False)
sorted('可迭代对象',key='函数名(函数名里写排序规则),reverse=True的时候是降序')

print(sorted(lst))

例子:使用sorted()函数来按照字典的value来对其进行排序

d = {
"v1": 80,
"v2": 20,
"v3": 40,
"v4": 20,
"v5": 10,
}
sorted_d = dict(sorted(d.items(), key=lambda item: item[1]))
print(sorted_d)

当然我们也可以使用itemgetter( )来替代上述 lambda函数,代码如下:

from operator import itemgetter
sorted_d = dict(sorted(d.items(), key=itemgetter(1)))
3. filter()过滤

函数可以是匿名,也可以是定义好的,得有判断条件  
语法: filter(function,iterable)

dic=[{'a':'d','s':15},{'d':'k','s':1}]
print(list(filter(lambda x:x['s']>5,dic)))
4.map() 映射函数,累加

语法: map(function,iterable)
一个列表中每个元素的平方

print(list(map(lambda x:x**2,lst)))
5.zip() 拉链

将对象中对应的元素打包成一个个元祖,返回的是对个,如果有三个可迭代对象,就按照最短的进行输出#4.

lst1 = [1,2,3]
lst2 = ['a','b','c','d']
lst3 = (11,12,13,14,15)


for i in zip(lst1,lst2,lst3):
    print(i)

结果:
(1, 'a', 11)
(2, 'b', 12)
(3, 'c', 13) 

6.enumerate(lst,10) #枚举

将可迭代对象放到里边,默认数字是0开始,自己指定开始的数字

li = ['x','a','sd']
for i,e in enumerate(li,10):
    print(i,e)
结果
"""
10 x
11 a
12 sd

"""
7.reduce 累计算 从python3中引入

语法:reduce(函数名,可迭代对象) # 这两个参数必须都要有,缺一个不行
第一次的时候 x是1 y是2 x乘以10就是10,然后加上y也就是2最终结果是12然后临时存储起来了
第二次的时候x是临时存储的值12 x乘以10就是 120 然后加上y也就是3最终结果是123临时存储起来了
第三次的时候x是临时存储的值123 x乘以10就是 1230 然后加上y也就是4最终结果是1234然后返回了

from functools import reduce
lst=[1,5,3]
print(reduce(lambda x,y:x*y,lst))

递归:

递 函数调用
归 函数的返回值
1)1.自己不断调用自己本身 -- 1,死递归
2.有明确的终止条件 -- 1,2 才是有效递归
2) 默认深度是1000 实际测试998
修改深度 import sys

import sys
sys.setrecursionlimit('修改的数量')

递归的应用: 文件查看 创建文件,删除文件

总结

迭代器:
具有 iternext 的就是迭代器
生成器一定是一个迭代器,迭代器不一定是生成器
具有 iternext,send 的就是生成器

区别

1.生成器和迭代器的区别:
迭代器必须是定义了__iter方法和__next方法的对象.它每次调用时会返回自身的下一个元素,比传统方式节省内存;
生成器是一次生成一个值的特殊类型的函数, 调用该函数将返回一个可用于生成连续某值的生成器.
生成器和迭代器应用场景
读取(获取)较大的文件和内容的时候使用,防止内存溢出

posted on 2020-02-25 16:17  xm微微一笑  阅读(105)  评论(0编辑  收藏  举报

导航