零基础学Python7——高阶语法(推导式,迭代器,生成器)

一.推导式

1.推导式介绍

python中有一种特有的语法,就是推导式(又称为解析式)。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。共有三种推导:列表推导式,字典推导式,集合推导式。

2.列表推导式

基本语法:[out_express for out_express in input_list]

例如:生成一个[0,1,4,9,16]的列表。使用列表推导式代码如下:

odd_list = [i*i for i in range(5)]
print(odd_list)

我们可以发现,列表推导式非常便利,如果是使用循环或许是需要几行代码才看可以实现,但是现在用一行代码就可以实现了。

并且当列表推导式还需要满足某条件下才可以输出表达式时,可以通过以下语法规范实现:

[out_express for out_express in input_list if out_express_condition]

例如:li = [6,2,6,7,-15,8,-17,-10,-15,-4],将列表中小于0的元素平方并保存到新列表中。

li = [6,2,6,7,-15,8,-17,-10,-15,-4]
new_li = [i**2 for i in li if i < 0]
print(new_li)

嵌套循环推导式:[i for row in matrix for i in row]

例子:生成列表 li 为 ['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c'] 代码如下:

li = [ i + j for i in '123' for j in 'abc']

2.字典推导式

基本语法:{out_exp_key: out_exp_value for out_exp in input_list}

例子:字典的key值为列表li的元素索引,字典的value值为列表的元素,li = ["age","name","gender"]

代码如下:

li = ["age","name","gender"]
dic = {li.index(i):i for i in li}
print(dic)

并且字典推导式可以快速将字典中的 k , v互换。代码如下:

dic1 = {0:"0",1:"1",2:"2"}
dic2 = {v:k for k,v in dic1.items()}
print(dic2)

3.集合推导式

基本语法:{out_exp_res for out_exp in input_set}

例子:随机生成10个 1 - 100之间的元素,并且去重

代码如下:

s1 = {random.randint(1,100) for i in range(10)}
print(s1)
print(len(s1))

最后需要注意的是python没有元组推导式,python的元组推导式叫做生成器,它与推导式又是另外一个区别。

二.迭代器

1.python迭代器

迭代器是指的是迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上一次结果而来的,迭代提供了一种通用的不依赖索引的迭代取值方式。

2.可迭代的对象

(1)可以用 for 循环遍历的对象都是可迭代的对象。

(2)str , list , tuple , dict ,set 等都是可迭代的对象。

(3)generator ,包括生成器和带 yield 的生成器函数。

3.判断是否可迭代

除了看内置是否有 __iter__ 方法来判断该对象是否是一个可迭代的对象之外,我么还可以使用 isinstance() 判断一个对象是否是 Iterable 对象。其中该函数用来判断是否是相应类型,与type()类似。

from collections import Iterable,Iterator
print(isinstance('abc',Iterable))   # True
print(isinstance([1,2,3,4],Iterable))   # True
print(isinstance(123,Iterable))     # False   

4.迭代器对象

(1)有内置的 __next__() 方法的对象,执行该方法可以不依赖索引取值。

(2)有内置的 __iter__()方法的对象,执行迭代器的 __iter__()方法得到的依然是迭代器本身。

需要注意的是可迭代的对象,不一定是迭代器。

from collections import Iterable,Iterator
li = [1,2,3,4]
print(isinstance(li,Iterator)) # False

5.iter()

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。那我们可以通过iter()方法将可迭代的对象,转为迭代器。

注意:迭代器不可以通过下标取值,而是使用__next__()或者next()函数。但是只要超出迭代器的范围就会直接报错。且next()只能顺延调用,不能往前。

print(lis[0])    # 报错 not subscriptable
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())

print(next(lis))
print(next(lis))
print(next(lis))
print(next(lis))  
print(next(lis))  #报错 'list_iterator' object is not subscriptable

 

6.可迭代对象和迭代器区别

(1)可用于 for 循环的都是可迭代类型

(2)作用于next()都是迭代器类型

(3)list,dict,str,等都是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器

(4)python的for循环本质就是通过不断调用next()函数实现的

三.生成器

1.生成器定义:

在python中,一边循环一边计算的机制,称为生成器:generator。

为什么要有生成器呢?

列表所有数据都在内存中,如果有海量数据的话会非常消耗内存。
比如说:我们仅仅需要访问前面几个元素,但后面绝大多元素占用的内存就会浪费了。

那么生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。

总而言之,就是当我们想要使用庞大数据,又想让它占用的空间少,那就使用生成器。

2.创建生成器

(1)生成器表达式:生成器表达式来源于迭代和列表解析的组合,生成器和列表类似,但是它使用的是()而不是[]。(与理论上的元组推导式类似)

g = (x for x in range(5))
print(g)       # generator object
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 超出报错
print(next(g))

for i in g:
    print(i)

3.生成器函数

当一个函数中包含 yield关键字,那么这个函数就不再是一个普通的函数,而是一个 generator。调用函数就是创建了一个生成器对象。其工作原理就是通过重复调用next()或者__next__()方法,直到捕获一个异常。

def yieldtest(number):
    n = 0
    # li = []
    while n<number:
        # li.append(n)
        yield n
        n+=1

res = yieldtest(3)
print(res)       # generator object
print(next(res)) # 0
print(next(res)) # 1
print(next(res)) # 2

注意:yield返回的是一个值,并且记住这个返回值的位置,下次遇到next()调用时,代码会从yield的下一条语句开始i执行。与return的区别是,return返回的也是一个值,但是直接结束函数。

例如:实现斐波那契数列,除了第一个和第二个数之外,任何一个数都可以由前两个相加得到,代码如下:

              
def createNums():
    print("-----func start-----")
    a,b = 0,1
    for i in range(5):
        # print(b)
        print("--1--")
        yield b
        print("--2--")
        a,b = b,a+b
        print("--3--")
    print("-----func end-----")
    
g = createNums()
print(next(g))  
print(next(g))  
print(next(g))
print(next(g))
print(next(g))

4.send()函数

send()和next()一样,都能让生成器继续往下走一步(遇到yield返回),但send()能传一个值,这个值作为yield表达式整体的结果。

def test():
    a1 = yield "hello"
    print("---1---")
    yield a1

res = test()
print(next(res))          # "hello"
print(res.send("world"))  # "world"

也就是说,通过send方法可以强行修改上一个yield表达式值。
比如函数中有一个yield赋值,a1 = yield "hello",第一次迭代到这里会返回"hello",但是a1还没进行赋值。第二次迭代时,使用.send("world"),那么,就是相当于强行修改yield "hello"表达式的值为"world",所以yield a1结果为"world"。

5.迭代器与生成器

(1)生成器能做到迭代器能做的所有事

(2)而且因为生成器自动创建了iter()和next()方法,生成器显得简洁,而且高效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值