zoukankan      html  css  js  c++  java
  • 装饰器 闭包 生成器 迭代器

    2018-02-21  16:15:56

    定义:本质是函数,(装饰其他函数)为其他函数增加附加功能

    装饰器原则

    1. 不能修改被装饰函数的源代码
    2. 不能修改被装饰函数的调用方式

    说白了,就是被装饰函数不知道装饰器的存在

    装饰器的知识储备

    函数即变量

    高阶函数

    把一个函数名当作实参传给另外一个函数

     def ball():
    # print('I am ball')
    # # return 15
    # def text11(hh):
    # hh()
    # text11(ball)
    # (函数后面有括号是这个函数本身和return,text11(ball())不符合高阶函数  没有括号是内存地址)

           

    返回值可以是函数名

    嵌套函数

     装饰器本质上是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值是一个函数对象. 经常用于有切面需求的场景,比如:插入日志,性能测试,事物处理,缓存,权限校验等场景. 装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续使用.   装饰器就是为已经存在的对象添加额外的功能

    @符号是装时器的语法糖,在定义函数时使用,避免再一次赋值操作

    1起源

    我们想在login中输入调试信息,我们可以这样做

    def login():
    print('in login')
    def printdebug(fun):
    print('enter the login')
    fun()
    print('exit the login')
    printdebug(login)

     2让代码变得优美一点

    def login():
    print('in login')
    def printdebug(fun):
    def a():
    print('enter the login')
    fun()
    print('exit the login')
    return a
    debug_login = printdebug(login)
    debug_login()

    3 让代码变得更加优美(python提供了@u语法糖符号)

    def printdebug(fun):
    def a():
    print('enter the login')
    fun()
    print('exit the login')
    return a
    @printdebug
    def login():
    print('in login')
    login()

    4.加上参数

    1)被装饰函数加参数

    python会将login的参数直接传给函数a. 我们可以在函数a中使用user变量

    def printdebug(fun):
    def a(user):
    print('enter the login in ')
    fun(user)
    print('exit the login')
    return a
    @printdebug
    def login(user):
    print('in login'+ user)

    4.2装饰器本身有参数(为了接受传来的参数,需要在原本的printdebug函数上面添加一个函数来接收参数)

    def printdebug_level(level):
      def printdebug(fun):
        def a(user):
          print('enter the login, and debug level is %s'%level)
          fun(user)
           print('exit the login')
        return a
      return printdebug
    @printdebug_level('it')
    def login(user):
      print('in login %s'%user)
    login('dsaf')
    5 装饰有返回值的函数(在装饰器中,将被装饰函数赋给一个变量,然后返回这个变量)

    def printdebug_level(level):
    def printdebug(fun):
    def a(user):
    print('enter the login, and debug level is %s'%level)
    fun(user)
    retuu = fun(user)
    print('exit the login')
    return retuu
    return a
    return printdebug
    @printdebug_level('it')
    def login(user):
    print('in login %s'%user)
    return '555'
    res = login('dsaf')
    print('my name is %s'%res)

    闭包

    如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,称为闭包
    def outter():
    name = 'slz'
    def inner():
    print(name)
    return inner
    res = outter()
    res()
    print(res.__closure__) 如果res是闭包的话,会返回一个由cell对象组成的元组对象
    print(res.__closure__[0].cell_contents) cell_contents属性是闭包中的自由变量

    
    
    列表生成器
    将列表中的每个值加一
    a = [i+1 for i in range(10)]
    print(a)

    生成器
    通过列表生成器,我们直接创建了一个列表.但是受到内存限制,列表容量肯定是有限是的.
    而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅访问前面的几个元素,那后面的大多数元素占用的空间就白白浪费了
    所以,如果列表和i元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
    这样就不必创建完整的list,从而节省大量的空间
    在python中,这种一边循环一边计算的机制,称为生成器: generator
    要创建一个generator,有很多种方法,第一种很简单,只要把列表生成式的[]改为()
    b = (i+1 for i in range(10))
    print(b)

    那么我们如何把b的值打印出来呢

    b = (i+1 for i in range(10))
    print(b)
    for n in b:
    print(n)

    定义generator的另一种方法,如果一个函数定义中包含yield关键字,那么这个函数就不在是一个普通函数,而是一个generator

    def fib(max):
        n,a,b = 0,0,1
    
        while n < max:
            #print(b)
            yield  b
            a,b = b,a+b
    
            n += 1
    
        return 'done' 
    还是通过循环来调用
    for i in fib(19):
    print(i)

    可迭代对象

    就是可以用for循环的
    for a in 'abc':
    print(a)
    一类是集合数据类型,list,tuple,dict,set,str
    一类是generator,包括生成器
    测试某个数据是否可迭代
    1,
    就是上面的可以直接作用于for循环的统称为可迭代对象: Iterable
    
    
    >>> from collections import Iterable
    >>> isinstance([], Iterable)
    True
    >>> isinstance({}, Iterable)
    True
    >>> isinstance('abc', Iterable)
    True
    >>> isinstance((x for x in range(10)), Iterable)
    True
    >>> isinstance(100, Iterable)
    False


    2 for i in 100:
    print(i)
    迭代器
    *可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

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

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> from collections import Iterator
    >>> isinstance((x for x in range(10)), Iterator)
    True
    >>> isinstance([], Iterator)
    False
    >>> isinstance({}, Iterator)
    False
    >>> isinstance('abc', Iterator)
    False
    通过上面的表可以看到list,dict,str虽然是Iterable,但不是Iterator

    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

    
    

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

    Iterator是只有需要返回下一步运算的时候才会计算

     

     小结

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

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

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

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

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

    实际上完全等价于:

    复制代码
    # 首先获得Iterator对象:
    it = iter([1, 2, 3, 4, 5])
    # 循环:
    while True:
        try:
            # 获得下一个值:
            x = next(it)
        except StopIteration:
            # 遇到StopIteration就退出循环
            break
  • 相关阅读:
    收藏文章
    Python __func__
    Python 可变对象 & 不可变对象
    Kafka SASL ACL配置踩坑总结
    C++ 传递动态内存
    负数取反,单目运算“-”的运算
    C++重载运算符的理解
    c++ 随机函数用法
    static变量
    路由汇聚及其相关计算
  • 原文地址:https://www.cnblogs.com/sunlizhao/p/8457446.html
Copyright © 2011-2022 走看看