设为首页 收藏本站
查看: 933|回复: 0

[经验分享] Python自动化开发学习4-2

[复制链接]

尚未签到

发表于 2018-8-11 07:37:45 | 显示全部楼层 |阅读模式
  列表生成式
  先看2段代码
  a = [ i*2 for i in range(10) ]
  print(a)
  #
  b = []
  for i in range(10):
  b.append(i*2)
  print(b)
  a和b的效果一样,但是a使用的代码更加简洁
  列表生成式也可以使用函数,生成更加复杂的列表
a = [ max(i,6) for i in range(10) ]  
print(a)
  上面的是铺垫,主要讲下面的生成器
  生成器
  用列表生成式,我们可以直接创建一个列表。等列表创建完之后,我们可以访问列表中的元素。但是这都得等列表生成完之后。如果列表很大很复杂,就需要耗费很长的时间和内存空间,然后我们才能访问列表中的元素。
  如果列表元素可以按照某种算法推算出来,我们不必创建完列表在进行后续的操作,而是一边循环一边引用每一个新创建的元素。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
a = [ i*2 for i in range(10) ]  
for i in a:
  
    print(i)
  
b = ( i*2 for i in range(10) )  # 这个是生成器
  
for i in b:
  
    print(i)
  
print(type(a),type(b))
  上面的代码中,a和b的效果是一样的。但是a的机制是先生成完整列表,再执行for循环。而b中只是记录了一个算法,并没有生成任何数据。等到for循环调用b的时候,才一边循环一边计算每一个元素。
  这里我们感觉不出两种机制的差别,但是当列表很大或者计算很复杂的情况下,就能发现两者的差别。我们强行来增加生成列表的时间。
import time  
def f(n):
  
    time.sleep(1)
  
    return n*2
  
a = [ f(i) for i in range(10) ]
  
for i in a:
  
    print(i)
  
b = ( f(i) for i in range(10) )  # 这个是生成器
  
for i in b:
  
    print(i)
  这下就发现区别了,a是等待了很长时间来生成列表,然后快速的把结果输出。而b是计算一个元素,输出一个元素,开始没有很长的等待时间,但是每次输出之间是要等待1秒来生成新的元素。
  顺便我看了一下两者的效率,理论上是差不多的,但是测试下来a要耗时10.02秒,b要耗时10.005秒。每次结果会不同,但是都在这个数字级别。
import time  
def f(n):
  
    time.sleep(1)
  
    return n*2
  
t = time.time()
  
a = [ f(i) for i in range(10) ]
  
for i in a:
  
    print(i)
  
print(time.time()-t)
  
t = time.time()
  
b = ( f(i) for i in range(10) )  # 这个是生成器
  
for i in b:
  
    print(i)
  
print(time.time()-t)
  看来使用生成器,也是一个更加效率的方法。
  生成器是一边循环一边计算的,所有的元素需要一个一个计算出来。只能一个一个的计算出来,并且只记住了当前的位置,在当前位置你只能取到下一个值,不能退回去,也不能跳过。
  所以,生成器只有一个方法.__next__
b = ( i*2 for i in range(10) )  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  
# 超出范围会报错
  上面好LOW,一般都用循环,__next__用的不是很多。
  在继续之前,先用函数写一个斐波那契数列。
  斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21,这个数列从第3项开始,每一项都等于前两项之和。
def fib(n):  
    i,a,b = 0,0,1
  
    while i < n:
  
        print(b)
  
        a,b = b,a+b
  
        i += 1
  
    return &quot;结束&quot;
  
fib(10)
  把上面的函数的print(b)替换成yield b,就实现了用函数做了一个生成器。
def fib(n):  
    i,a,b = 0,0,1
  
    while i < n:
  
        #print(b)
  
        yield b  # 替换成这句
  
        a,b = b,a+b
  
        i += 1
  
    return &quot;结束&quot;
  
f = fib(10)
  
print(type(f))  # f的数据类型是generator
  这是定义生成器的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个生成器。
  生成器在语句执行遇到yield的时候会返回,但是会记住当前的位置,如果你使用.__next__()则会在之前的位置继续执行。也就是生成器在执行并且返回之后,并没有完全结束。跳出生成器后可以正常执行别的语句,在需要的时候再从之前生成器返回的位置继续执行下一次循环。这样的话生成器最后的return就没有意义了。接着看,我们先试着打印出生成器中的所有元素。
def fib(n):  
    i,a,b = 0,0,1
  
    while i < n:
  
        #print(b)
  
        yield b
  
        a,b = b,a+b
  
        i += 1
  
    return &quot;结束&quot;
  
f = fib(10)
  
print(type(f))
  
print(f.__next__())
  
print(&quot;你可以随时插入你的语句&quot;)
  
print(f.__next__())
  
print(&quot;生成器会记住之前的位置继续循环&quot;)
  
print(f.__next__())
  
print(f.__next__())
  
print(f.__next__())
  
print(f.__next__())
  
print(f.__next__())
  
print(f.__next__())
  
print(f.__next__())
  
print(&quot;打了那么多就是要超出限制&quot;)
  
print(f.__next__())
  
print(f.__next__())
  如果超出了继续取,就会报错。仔细看一下报错的内容,最后的StopIteration:后的内容就是你return的内容。我们可以用try来捕获这个错误从而获取return的值。try还没讲到,后面应该会细讲。
def fib(n):  
    i,a,b = 0,0,1
  
    while i < n:
  
        #print(b)
  
        yield b
  
        a,b = b,a+b
  
        i += 1
  
    return &quot;结束&quot;
  
f = fib(10)
  
while 1:
  
    try:
  
        x = next(f)  # x = f.__next__()
  
        print(x)
  
    except StopIteration as e:
  
        print(&quot;返回值是:&quot;,e.value)
  
        break
  这里x=next(f)和x=f,__next__()效果一样。这里上课没讲,暂时没发现有什么区别。
  通过yield还可以实现单线程下的并行效果,这个不叫并行,叫协程。这里好烦,直接抄老师的例子了。
import time  
def consumer(name):
  
    print(&quot;%s 准备吃包子啦!&quot; %name)
  
    while True:
  
       baozi = yield  # 这里中断,通过send传值进来继续执行
  
       print(&quot;包子[%s]来了,被[%s]吃了!&quot; %(baozi,name))
  
def producer(name):
  
    c = consumer('A')  # 定义了一个consumer('A'),但是并没有运行
  
    c2 = consumer('B')  # 定义了一个consumer('B')
  
    c.__next__()  # consumer('A')启动运行,运行到yield之前,打印&quot;准备吃包子啦&quot;
  
    c2.__next__()  # consumer('B')启动运行
  
    print(&quot;老子开始准备做包子啦!&quot;)
  
    for i in range(10):
  
        time.sleep(1)
  
        print(&quot;做了2个包子!&quot;)
  
        c.send(i)  # send是给yield传值
  
        c2.send(i)
  
producer(&quot;C&quot;)
  上面的例子里.send(i)之前没提过,和.__next__()一样,但是sent可以传一个值回去。
  上面的例子就是producer启动以后,又启动了2个consumer。consumer运行到yield中断,等待。producer将值通过send传给consumer后,consumer就执行一次循环,然后再中断,等待新的值传入。
  迭代器
  可直接作用于for循环的对象,统称为可迭代对象:Iterable
  使用下面这个方法可以判断一个对象是否迭代
from collections import Iterable  
print(isinstance('',Iterable))  # 字符串可迭代
  
print(isinstance(123,Iterable))  # 数字不可迭代
  
print(isinstance((),Iterable))
  
print(isinstance([],Iterable))
  
print(isinstance({},Iterable))
  
print(isinstance((x for x in range(10)),Iterable))  # 这个是生成器,可迭代
  生成器不但可以作用于for循环,还可以next,不断调用返回下一个值。
  可以被__next__()调用并不断返回下一个值的对象称为迭代器:Iterator
  使用下面的方法再判断一下之前的对象是否是迭代器
from collections import Iterator  
print(isinstance('',Iterator))
  
print(isinstance(123,Iterator))
  
print(isinstance((),Iterator))
  
print(isinstance([],Iterator))
  
print(isinstance({},Iterator))
  
print(isinstance((x for x in range(10)),Iterator))
  只有最后一个可以__next__(),只有最后一个是True,是迭代器。
  上面的这些可迭代对象,目前都不是迭代器。通过iter()就可以把这些可迭代对象变成迭代器。
from collections import Iterator  
a = [1,2,3,4,5,6]
  
print(isinstance(a,Iterator))
  
b = iter(a)
  
print(isinstance(b,Iterator))
  
print(b.__next__())
  
print(b.__next__())
  
print(b.__next__())
  Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。这样,迭代器甚至可以表示一个无限大的数据流。
  我们的for循环,本质上就是通过不断调用next来实现的。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-549855-1-1.html 上篇帖子: python时间模块time和datetime-506554897 下篇帖子: Python中的循环退出举例及while循环举例
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表