zoukankan      html  css  js  c++  java
  • python -- 迭代器和装饰器

    迭代器和装饰器在python中的使用十分常见,下面是个人对迭代器和装饰器的理解

    迭代器

      1、迭代器 iter 的特点:

        (1).访问者不需要关心迭代器的内部结构,仅需要通过__next__()方法不断去取下一个内容
        (2).不能随机访问集合(不是set,只是一些元素的聚集体)中的某个值,只能从头到尾依次访问
        (3).访问到一半时不能后退(过去的就过去了,不能回头)
        (4).便于循环比较大的数据集合,节省内存(每次需要了指定数据时,才把该读取到内存中,eg:迭代文件时,内存中每一时刻都只有文件的一行)

    1 a = iter(['root','admin','python','ruby' ])    #生成一个迭代器
    2 print(a.__next__())   
    3 print(a.__next__())      #只有一个__next__() 方法
    4 print('waitting!')    #在第二代的过程中,能停下来做其他的事
    5 print(a.__next__())     
    6 print(a.__next__())
    7 #print(a.__next__())    #报错 超出迭代器范围

      常见迭代器使用:
        读文件时:
          with open('a*.txt','r+') as f:
            for line in f:
            ...
        这里的for i in f:就是用的迭代器,避免依次把文件内容全部读取到内存中,节省内存。

    在介绍迭代器时,还有个概念要明白,何为生成器

      生成器 generator
      定义: 一个函数调用时返回一个迭代器,那么这个函数就叫做生成器,如果函数中包含了yield语法,那么这个函数就会变成一个生成器(保存函数的中断状态)

     1 >>> 
     2 >>> def test_yeild(n):
     3     while n > 0:
     4         n -= 2
     5         yield 10
     6         print('注意何时打印这句话...')
     7 
     8         
     9 >>> t = test_yeild(12)      # 与普通函数不同,这里只是生成一个迭代器,不会跳到‘函数体’里面去(执行函数体),而是等待迭代器的__next__()方法
    10 >>> t.__next__()
    11 10                # 返回yield后面的值,并在执行完yield后 暂停程序 ,等待下一次__next__(),然后接着从暂停的地方开始运行
    12 >>> t.__next__()          
    13 注意何时打印这句话...
    14 10
    15 >>> t.__next__()
    16 注意何时打印这句话...
    17 10
    18 >>> t.__next__()
    19 注意何时打印这句话...
    20 10
    21 >>> t.__next__()
    22 注意何时打印这句话...
    23 10
    24 >>> t.__next__()
    25 注意何时打印这句话...
    26 10
    27 >>> t.__next__()
    28 注意何时打印这句话...
    29 Traceback (most recent call last):
    30   File "<pyshell#162>", line 1, in <module>
    31     t.__next__()
    32 StopIteration
    33 >>> 

    yield 可以返回一个值,也可以接收一个值,给yield传值用send()

    看下面例子,用yield做了个简单的异步操作:

     1 import time
     2 
     3 def consumer(name):
     4     print("%s 准备吃包子啦!" %name)
     5     while 1:
     6         baozi = yield
     7         print("包子[%s]来了,被[%s]吃了" %(baozi,name))
     8         
     9 def producer(name):
    10     c = consumer('A')
    11     c2 = consumer('B')
    12     c.__next__()
    13     c2.__next__()
    14     print("%s开始准备做包子啦!" %name)
    15     for i in range(3):
    16         time.sleep(1)        #执行时为了更清楚的看到过程
    17         print("做了2个包子")
    18         c.send(i)
    19         c2.send(i)
    20               
    22 producer('root')

    A 准备吃包子啦!
    B 准备吃包子啦!
    root开始准备做包子啦!
    做了2个包子
    包子[0]来了,被[A]吃了
    包子[0]来了,被[B]吃了
    做了2个包子
    包子[1]来了,被[A]吃了
    包子[1]来了,被[B]吃了
    做了2个包子
    包子[2]来了,被[A]吃了
    包子[2]来了,被[B]吃了
    

      

     1 def account(money):
     2     while money > 0:
     3         out_money = yield 
     4         money -= out_money
     5         #yield 300
     6         print('又来取钱了!取了%s' %out_money)
     7         
     8 atm = account(1500)
     9 atm.__next__()
    10 for i in range(5):
    11     atm.send(300)
    12     #在第一次用__next__()方法启动迭代器后,每次调用迭代器,就会自动执行__next__()方法
    13     

    装饰器

      装饰器基本功能:对已有函数进行扩展

      (个人初步理解,可能错误)
      装饰器执行过程:
        1.在调用被装饰器装饰的函数时,先把被装饰器装饰的函数(装饰器下一行代码中函数)的函数名传递给装饰器从内到外第二层定义的函数
        2.把被装饰器装饰的函数的实参传递给装饰器最内层函数
        3.在装饰器内部实现被装饰器装饰的函数的调用

     简单装饰器:

     1 def login(func):
     2     def inner(*args,**kwargs):
     3         print("我是做身份验证的,验证成功才能调用函数")
     4         print(args,kwargs)
     5         func(*args,**kwargs)
     6         #return func(*args,**kwargs)
     7     return inner
     9     #若传进来的是函数名,那么没有执行'()'的话,即是函数的内存地址
    10 
    11 #@login    #(装饰器)程序一执行,就会调用装饰器的函数
    12 def home(name):
    13     print("welcome [%s] vidited the home page" %name)
    14 
    15 @login   #@符号的作用: 相当于执行 tv = login(tv) 
    16 #def tv(name,passwd=123):
    17 def tv(*args,**kwargs):
    18     print("welcome [%s] vidited the tv page" %args )
    19     #若这里有返回值,则仅需要在inner里面返回函数结果
    20 #@login
    21 def movices(name):
    22     print("welcome [%s] vidited the movices page" %name)
    23     
    24 tv('root')
    25 tv('xtsec',passwd=123)

    复杂装饰器:

     1 '''
     2 调用装饰器时(eg:@login(f1,f2)),传递多个参数的装饰器(三层装饰器)
     3 '''
     4 def before():
     5     print("执行要装饰的函数之前执行")
     6 
     7 def affter():
     8     print("执行要装饰的函数之后执行")      #没有return的函数默认返回None
     9 
    10 def test_ge(before1,affter1):
    11     def login(func):
    12         def inner(*args,**kwargs):
    13             result_before = before1()
    14             if(result_before != None):     
    15                 return '执行before条件未成功!'    #这里运行就表示before函数没有正确运行结束,所以表示验证没通过
    16             ret = func(*args,**kwargs)
    17             if(ret != None):
    18                 return '执行被修饰函数不成功!'    #若前面验证通过,且装饰器正确执行,到这里整个装饰器运行结束
    19             result_afftr = affter1()
    20             if(result_afftr != None):
    21                 return '执行时不满足要求!'     #若前面装饰器修身的函数没正确运行,就会到这里,常用来返回错误信息
    22             return ret
    23         return inner
    24     return login
    25 
    26 def home(name):
    27     print("welcome [%s] vidited the home page" %name)
    28 
    29 '''
    30 接下来这一行有三个操作:
    31 1.调用函数 test_ge(before, affter)
    32 2.@login   login为调用test_ge(before, affter)的返回值
    33 3.新tv = inner    login()的返回值
    34 '''
    35 @test_ge(before, affter)   
    36 def tv(*args,**kwargs):
    37     print("welcome [%s] vidited the tv page" %args )
    38     return 1
    39 
    40 def movices(name):
    41     print("welcome [%s] vidited the movices page" %name)
    42 
    43 
    44 tv('root',passwd='admin')   
    45     #在这里执行tv()时,事实上时执行新的tv(),即是inner()
    46 a = before()
    47 print(type(a),a)
    48 if a == None:
    49     print('110')

    在日常使用中,一般就用普通的装饰器,复杂度这个最好明白运行原理即过程

  • 相关阅读:
    linux时间同步,ntpd、ntpdate
    重启HPE管理芯片ILO5的5种方法(Reset ilo)
    Linux内核SPI支持概述
    linux 查看CPU详情命令
    高可用
    NFS的介绍
    SELINUX
    error: undefined reference to 'android::hardware::details::return_status::~return_status()'
    errors collectiions
    大型分布式架构设计与实现-第三章互联网安全架构
  • 原文地址:https://www.cnblogs.com/xtsec/p/6682331.html
Copyright © 2011-2022 走看看