全面理解python之装饰器、生成迭代器、上下文管理器以及惰性计算

本文主要讲解装饰器、迭代器、生成器、上下文管理器以及惰性计算


装饰器(decorator)
  • 功能:增加函数的功能,而不引入多余的变量,不需要修改原来的函数;

  • 实现:利用@语法糖,将被装饰函数作为第一位置参数传给装饰器;

    def dec1(func):
        print("2")
        def one():
            print("3")
            func()
            print("6")
        return one
    
    def dec2(func):
        print("1")
        def two():
            print("4")
            func()
            print("5")
        return two
        
    @dec1
    @dec2
    def test():
        print("hello world!")
        
    test()
    

    输出:

    1
    2
    3
    4
    hello world!
    5
    6
    
  • 模块加载与导入时立即执行,不需要显示的调用

  • 利用闭包可以实现带参数的装饰器

迭代器(iterator)
  • 可迭代对象: 可返回迭代器的对象,如容器中的list、dict、set、str;
  • 迭代器: 用iter()封装可迭代对象,用next()访问元素;
  • 任何实现了__iter__()和__next__()方法的对象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常;
    >>> x = [1, 2, 3] # x为容器
    >>> y = iter(x)  # y为迭代器
    >>> z = iter(x) # z与y独立
    >>> next(y) # 调用迭代器
    1
    >>> next(y)
    2
    >>> next(z)
    1
    
  • 优点: 不要求事先准备好整个迭代过程中所有的元素,适合于非常大的序列的访问;
  • for循环: 作用于可迭代对象,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取下一个元素;
生成器(generator)
  • 迭代器实现起来有些繁琐,生成器则自动的实现了迭代器协议,一边循环,一边计算;

两种实现方式:

  • 1 yield: 生成器函数,暂时,下次继续

    def f():
        yield 1
        yield 2
        yield 3
    f1=f()
    print([next(f1) for i in range(2)])
    输出:[1, 2]
    
  • 2 generation expression: 生成器表达式,用(),与list不同;

    >>> a = (x for x in range(10))
    >>> next(a)
    0
    >>> next(a)
    1
    >>> next(a)
    2
    
  • 生成器本身是一个迭代器,可用next()调用

    >>> from collections import Iterable
    >>> isinstance((x for x in range(10)), Iterable)
    True
    
  • 生成器生成斐波那契数列

    def fibonacci():
        a = [1, 1]
        while True:
            a.append(sum(a))
            yield a.pop(0)
    for x in fibonacci():
        print(x)
        if x > 50:
            break
    

    输出:

    1
    1
    2
    3
    5
    8
    13
    21
    34
    
  • 生成器好处: 相比起list,能节省大量内存,尤其是对于无法在内存中存放的无限数据流

上下文管理器(context manager)
  • 有始必有终的代码使用,非常pythonic,减少错误,提高可读性;
  • 为什么需要:程序运行中突然中断或出现bug,比如写入文件,加了上下文管理器可以将后续关闭文件等操作完成,类似于try/finally,否则则不会保存;
    with open(path, mode) as f:
        f.read()
    

执行时机:

  • __init__():进入with语句时执行
  • __enter__():进入with代码块之前执行
  • __exit__():离开或者突然中断时先执行

计时:

import time
class timer:
    def __init__(self, name):
        self.name=name
    def __enter__(self):
        self.start=time.time()
    def __exit__(self):
        self.end=time.time()
        self.interval = self.end - self.start
        print("%s took: %0.3f seconds" % (self.name, self.interval))
with timer("sleep 3 seconds"):
    time.sleep(3)
惰性计算
  • 函数在定义的时候,并没有分配内存空间用来保存任何变量的值,只有在执行的时候,才会分配空间,保存变量的值
    >>> a = [lambda :x for x in range(10)]
    >>> a[0]()
    9
    >>> a[9]()
    9
    
    解释:首先这是个列表解析表达式,列表中的每一个元素是一个函数,返回x的值,但没有执行函数调用的时候,是没有x的值的;
    当后续调用时,for循环中的x对于所有的函数是公用的,此时的x的值已经变为9,因此无论调用哪个元素,结果都为9;
  • 同样的例子:
    flist = []
    for i in range(3):
        def foo(x): print x + i
        flist.append(foo)
    for f in flist:
        f(2)
    
    输出:
    4
    4
    4
    
  • 生成器与迭代器,处理无限的数据流时,逐个计算;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值