python函数:迭代器,生成器,推导式

mac2024-01-26  33

内置函数

filter(函数,可迭代对象)

map(函数,可迭代对象)

sorted(值,key=指定排序规则,reverse=True)

reversed(值)zip(值,值,值)

reduce(函数,可迭代对象)

zip(值,值,值)

迭代器

可迭代对象

能够for循环的就是一个可迭代对象具有__iter__方法的就是可迭代对象

迭代器

在上次停留的位置继续去做一些事情

lst = ["a","b","c","d","e","f"] lst1 = lst.__iter__() #创建了一个迭代器 print(id(lst)) #查看lst的内存地址 print(id(lst[0])) #查看lst[0]的内存地址 print(lst1) #迭代器的内存地址 print(lst1.__next__) print(list(lst1)) # 将迭代器转换成了一个列表 结果: 264140179464 264139523944 <list_iterator object at 0x0000003D7FFB0198> 'a' ['a', 'b', 'c', 'd', 'e', 'f']

根据以上代码,迭代器我判断就是开辟新的内存地址,然后指向了原来的那个列表

for循环的本质

lst = [1,2,3,1,4,5,6,7] #新建一个列表 lst1 = lst.__iter__() #创建一个迭代器lst1 while True: try: print(lst1.__next__()) #输出迭代的值 except:StopIteration #如果遇到这个错误就结束

迭代器在次迭代还是原来那个迭代器

lst = [1,2,3,1,4,5,6,7] #新建一个列表 lst1 = lst.__iter__() #创建一个迭代器lst1 print(lst1) print(lst1.__iter__()) #迭代器在次迭代还是原来的值 结果: <list_iterator object at 0x00000083C34200B8> <list_iterator object at 0x00000083C34200B8>

具有__iter__()方法的就是一个可迭代对象

迭代器具有__iter__() 和__next__()

迭代器一定是一个可迭代对象,但是可迭代对象不一定是一个迭代器

可迭代对象的优点

方便查找使用灵活

可迭代对象的缺点

占内存

迭代器的优点

节省内存–惰性机制

迭代器的缺点

查找不方便使用不灵活一次性的不能后退

迭代器是Python自己提供的一种节省空间的方式

生成器

生成器的本质就是迭代器

迭代器是Python自带的

生成器是程序猿自己写的

生成器如何编写

基于函数编写生成器

def func(): yield 1 g = func() print(g) print(g.__next__()) print(g.__iter__()) 结果: <generator object func at 0x000000B9116A2E60> 1 <generator object func at 0x000000F585EF2E60>

yield相当于return

一个yield对应一个next

怎么区分迭代器和生成器

通过内存地址来分辨

迭代器:<list_iterator object at 0x00000091FE4402B0>

生成器:<generator object func at 0x00000091FE402E60>

后面的地址是变化的,只是拿了最前面的做判断

通过send()方法来分辨

迭代器没有send()方法

生成器有send()方法

生成器节省空间

时间换空间 :

空间换时间 :

当文件或数据量较大时使用生成器

yield from和yield的区别:

yield后边的内容整体返回

yield from将可迭代对象中的元素逐个返回

推荐使用iter()和next()

基于推导式

推导式

列表推导

普通模式:

print([i for i in range(10)]) 结果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

筛选模式:

#[加工后变量 for循环 加工条件] print([i for i in range(10) if i > 5]) print([i for i in range(10) if i % 2 == 1]) print([i%2 for i in range(10)])

字典推导

普通模式

print({i:i+1 for i in range(10)}) 结果: {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}

筛选模式

print({i:i+1 for i in range(10) if i == 3}) 结果: {3: 4}

集合推导

普通模式

print({i for i in range(10)}) 结果: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

筛选模式

print({i for i in range(10) if i > 5 and i > 7}) 结果: {6}

生成器推导

普通模式

g = (i for i in range(10)) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) 结果: 0 1 2 3 4

筛选模式

g = (i for i in range(10) if i - 6 == 2) print(next(g)) 结果: 8

面试必考

第一题: lst = [lambda x:i for i in range(5)] #将推导式的地址赋值给Lst #次行是先执行完for循环,然后去下面接着执行 print(lst) print([em(1) for em in lst]) # [4,4,4,4,4] 执行一次循环,使用一次em,去调用一次50行,不断调用 第二题: lst = [] for i in range(5): lst.append(lambda x:i) #添加进去的是每个元素的地址 五次执行完毕,匿名函数的返回值最后是i,由于for循环完的时候I的值是4 print(lst) #每个元素的地址 第三题: new_lst = [] for em in lst: new_lst.append(em(1)) # 调用em()函数就是调用lst里面的地址对应的值,但是em()的返回值是4,所以不论执行多少次,他始终添加的值为4 print(new_lst) #[4, 4, 4, 4, 4] 第四题: lst = [lambda :i+1 for i in range(3)] #lst拿了匿名函数的地址0 1 2的内存地址,返回的值为i+1 i为2 for i in lst: print(i) print({em():em()+1 for em in lst}) #首先此循环会执行三次,因为Lst里面有三个内存地址,但是i的值此时为2,所以返回的就是3:4。因为是字典,字典会存在key值得之后自动赋值新值,所以最后的4是最后一次循环的值 第五题: g = (lambda x:x+i for i in range(3)) # 惰性 生成器推导需要每次用的时候才会执行,不执行自己永远不会动 print([em(2) for em in g]) # [4,4,4] #此题我故意给的错误答案,若要看正确的,请看下面的详细分析。 """ 第一次: [em(2) for em in g] 使用到g,g拿到的是推到器推导到的内存地址,所以去了推到器推导进行分析 此时第一次i的值为0,传递的实参为2,所以返回值x+i的值为2 第二次: [em(2) for em in g] 使用到g,g拿到的是推到器推导到的内存地址,所以去了推到器推导进行分析 此时第二次i的值为1,传递的实参为2,所以返回值x+i的值为3 第三次: [em(2) for em in g] 使用到g,g拿到的是推到器推导到的内存地址,所以去了推到器推导进行分析 此时第三次i的值为1,传递的实参为2,所以返回值x+i的值为4 """ def func(): for i in range(3): yield lambda x:x+i #yield保存上一次取得地址,下次来了直接Next g = func() #g拿到的是func的内存地址 print(g) lst = [] for em in g: lst.append(em(2)) #2 3 4 print(lst) g = [lambda x:x+i for i in range(3)] #g拿到的是lambda的三个内存地址,此时I的值为2 print([em(2) for em in g]) # [4,4,4] g = (lambda x:x+i for i in range(10)) # 惰性 print([next(g)(2) for em in range(5)]) #[2, 3, 4, 5, 6]
最新回复(0)