python列表推导式随机数列_Python函数——列表推导式、生成器与迭代器

列表推导式

产生背景

现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1,你怎么实现?

第一种方法:

a = [1,3,4,6,7,7,8,9,11]for ind, val inenumerate(a):

a[ind]+= 1

print(a)

第二种方法:

a = [1,3,4,6,7,7,8,9,11]print(list(map(lambda x: x+1, a)))

列表推导式:

a = [1,3,4,6,7,7,8,9,11]print([i+1 for i in a])

使用列表推导式可简化代码。用法如下

例一:30以内所有能被3整除的数

print([i for i in list(range(31)) if i % 3 ==0])#使用if 表达式

例二:30以内所有能被3整除的数的变为平方,否则乘以2

#使用三元表达式

print([i*i if i % 3 == 0 else i*2 for i in list(range(31))])

练习题:

"""例1: 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母

例2: 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表

例3: 求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]"""str_li= ['abc', 'cd', 'xy']print([x.upper() for x in str_li if len(x) >= 3])print([(x, y) for x in list(range(6)) if x % 2 == 0 for y in list(range(6)) if y % 2 == 1])

M= [[1,2,3],[4,5,6],[7,8,9]]print([row[2] for row in M])

字典推导式

例一:将一个字典的key和value对调

#

mcase = {'a': 10, 'b': 34}print({mcase[k]: k for k in mcase})

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,

如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?

这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

生成器的创建方式

1. 类似于列表生成式()

2. 函数中使用yield

函数有了yield之后

1. 函数调用之后就得到了一个生成器,

2. return 在生成器里,代表生成器的中止,直接报错3.yield 返回数据 ,并冻结当前的执行过程 。。

类似于列表生成式()创建

L = [x * x for x in range(10)]

gen_L= (x * x for x in range(10)) #生成器存放计算公式

print(L)print(gen_L)print(next(gen_L)) #取值

print(next(gen_L))"""[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

at 0x0000000001DFDF10> generator 就是生成器的意思

0

1"""

generator保存的是算法,每次调用next(g)就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误,使用for循环可以解决异常

g = (x * x for x in range(10))for n ing:print(n)

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

deffib(max):

n, a, b= 0, 0, 1

while n

print(b)

a, b= b, a +b

n= n + 1

return 'done'f= fib(15) #turn function into a generator

next(f) #first time call next() next 唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield

next(f) #first time call next()

"""before yield

1

before yield"""

注意a, b = b, a + b 相当于

a, b = 0, 1a, b= b, a +bprint(a, b)

a, b= 0, 1

t = a

a = b

b = t + bprint(a, b)"""1 1

1 1"""

函数方式创建

defrange2(n):

count=0while count

stop_flag= yield count #中断并返回

returncountif stop_flag == 'stop':print('stop iteration...')breakcount+= 1b= range2(5) # 得到生成器

next(b)

next(b)"""0

Traceback (most recent call last):

File "C:/Users/jingjing/PycharmProjects/py3Project/路飞/第二模块/函数练习/生成器.py", line 53, in

next(b)

StopIteration: 0"""

生成器常用方法

next() # 唤醒生成器并继续执行

send("stop")"""1. 唤醒并继续执行

2. 发送一个信息到生成器内部

注意生成器在刚开始,函数没有执行到yield成为挂起状态时,不能调用send("stop")

只能send('None')相当于next()使函数执行到yield"""

send使用举例

defrange2(n):

count=0while count

count+= 1sign= yield count #return

if sign == 'stop':print("---sign", sign)break

print('sin...', sign)return 3333new_range= range2(3)

next(new_range)

new_range.send(None)

new_range.send("stop")"""count 0

sin... None

count 1

---sign stop

Traceback (most recent call last):

File "C:/Users/jingjing/PycharmProjects/py3Project/路飞/第二模块/函数练习/函数生成器.py", line 22, in

new_range.send("stop")

StopIteration: 3333"""

生产者与消费者问题

importtimedefconsume(name):print("%s 准备吃包子啦!" %name)whileTrue:

y= yield

print("包子[%s]来了,被[%s]吃了!" %(y, name))defproducer(name):

c=consume(name)

next(c)#函数执行到yield

for i in range(1, 3):

time.sleep(1)print("做了{}个包子!".format(i))

c.send(i)#把i传到yield

producer('qian')"""qian 准备吃包子啦!

做了1个包子!

包子[1]来了,被[qian]吃了!

做了2个包子!

包子[2]来了,被[qian]吃了!"""

日志记录

deflogger(filename):"""日志方法

:param filename: log filename

:param channel: 输出的目的地,屏幕(terminal),文件(file),屏幕+文件(both)

:return:"""

print('start logger')whileTrue:

msg= yield

print("msg", msg)

l= logger('USER.TXT')

l.__next__()

l.send('hi')

l.send('hi,file')

计算移动平均值

#必须先用next再用send

defaverage():

total=0 #总数

day=0 #天数

average=0 #平均数

whileTrue:

day_num= yield average #average=0

print('average', average)

total+=day_num

day+= 1average= total/day

avg=average() #直接返回生成器

next(avg)#激活生成器,avg.send(None),什么都不传的时候send和next的效果一样

print(avg.send(10))print(avg.send(20))#send 1.传值 2.next

print(avg.send(30))"""average 0

10.0

average 10.0

15.0

average 15.0

20.0"""

带装饰器的计算移动平均值

#让装饰器去激活

defwrapper(func):def inner(*args, **kwargs):print('execute wrapper')

a= func(*args, **kwargs)

next(a)returnareturninner

@wrapperdefaverage():

total=0 #总数

day=0 #天数

average=0 #平均数

whileTrue:

day_num= yield average #average=0

print('average', average)

total+=day_num

day+= 1average= total/day

avg=average()print(avg.send(10))print(avg.send(20))#send 1.传值 2.next

print(avg.send(30))"""execute wrapper

average 0

10.0

average 10.0

15.0

average 15.0

20.0"""

yield from

defgen1():for c in 'AB':yieldcfor i in range(3):yieldiprint(gen1())print(list(gen1()))defgen2():yield from 'AB' #相当于 for c in 'AB': yield c

yield from range(3)print(gen2())print(list(gen2()))

处理异常

deffib(max):

n, a, b= 0, 0, 1

while n

a, b = b, a +b

n= n + 1

return 'done'g= fib(6)whileTrue:try:

x=next(g)print('g:', x)exceptStopIteration as e:print('Generator return value:', e.value)break

生成器小结

生成器的创建方式

1. 类似于列表生成式()

2. 函数中使用yield优点:节省内存空间

函数有了yield之后

1. 函数调用之后就得到了一个生成器,

2. return 在生成器里,代表生成器的中止,直接报错

注意

python3 range相当于python2 xrange 生成器

python2 range相当于list

yield vs return

return 返回并中止function

yield 返回数据 ,并冻结当前的执行过程 。。

生成器常用方法

1.next()

2.send("stop")

"""

1. 唤醒并继续执行

2. 发送一个信息到生成器内部

注意生成器在刚开始,函数没有执行到yield成为挂起状态时,不能调用send("stop")

只能send('None')相当于next()使函数执行到yield

"""

迭代器

可迭代对象与迭代器

迭代:可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。就像for循环一样取值。

可迭代协议:可以被迭代要满足要求的就叫做可迭代协议。内部实现了__iter__方法

iterable:可迭代的------对应的标志

字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。

可以使用isinstance()判断一个对象是否是Iterable对象:

from collections importIterableprint(isinstance([], Iterable))print(isinstance(123, Iterable))print(isinstance('345', Iterable))#"""#True#False#True#"""

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了

迭代器协议:内部实现了__iter__,__next__方法。

迭代器的优点:如果用了迭代器,节约内存,方便操作,生成器是一种迭代器(Iterator)。

可迭代和迭代器的相同点:都可以用for循环

可迭代和迭代器的不同点:就是迭代器内部多实现了一个__next__方法

判断迭代器和可迭代的方法:

第一种:判断内部是不是实现了__next__方法

print('__next__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__

print('__iter__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__

第二种:

Iterable 判断是不是可迭代对象

Iterator 判断是不是迭代器

from collections importIterablefrom collections importIterator#比如给一个字符串

s='abc'

print(isinstance(s,Iterable))#isinstance判断类型的

print(isinstance(s,Iterator))

判断range函数和map函数

深入了解Iterator对象

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator可以使用iter()函数:

你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,

直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,

只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

迭代器小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python3的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:pass

等价于

#首先获得Iterator对象:

iter_object = iter([1, 2, 3, 4, 5])#循环:

whileTrue:try:#获得下一个值:

x =next(iter_object)exceptStopIteration:#遇到StopIteration就退出循环

break

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值