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')

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

  • 相关阅读:
    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js
  • 原文地址:https://www.cnblogs.com/xtsec/p/6682331.html
Copyright © 2011-2022 走看看