zoukankan      html  css  js  c++  java
  • python基础(八)生成器,迭代器,装饰器,递归

    生成器

    在函数中使用yield关键字就会将一个普通的函数变成一个生成器(generator),普通的函数只能使用return来退出函数,而不执行return之后的代码.而生成器可以使用调用一个next方法来返回生成器中上一次yield时候的状态.并且可以使用send方法给yield重新赋值.这样就可以灵活的进入和跳出函数.因此在程序中生成器可以中断当前函数,去执行其它的代码,在合适的时候跳回函数继续执行

    def yield_test():
        print('befor the first')
        first = yield
        print(first)
        print('before the second')
        second = yield
        print(second)
        print('before the Third')
        Third = yield '也可以有返回值'
        print(Third)
        print('after the Third')
        
    #next方法
    g = yield_test()
    g.__next__()
    g.__next__()
    yield_text = g.__next__()		#获取yield传出的数据,接受数据next和发送数据yield的位置顺序相同
    print(yield_text)
    # g.__next__()
    
    #send方法
    g = yield_test()
    g.__next__()     				#做实验时第一次必须是next,send会报错
    g.send('2222')					#send发送的数据会被赋值给当前yield之前的代码中生效.
    								#简单说是赋值给前一个yield以便本次代码执行
    g.send('3333')
    
    

    补充:通过这个例子我们发现
    1,send方法被生成器当作了一次__next__,并且send的值会复制给上一个yield,
    2,yield和__next_方法是一一对应.当next比函数内yield多时,最后一个next会报一个StopIteration异常.
    3,yield后的代码会在下一次next调用时才会执行.
    4,yield可以发送数据,也可以接受数据.获取数据时要注意传入和传出不同时机才能获取正确的yield值

    所以我们通常把生成器用在可循环的对象

    def read_file():
        read_size = 10
        with open('test.txt','rb') as f:
            while True:
                text = f.read(read_size)
                yield text		#通过yield获取当前的text值
    
    g = read_file()			
    while True:
        print(g.__next__())
    #生成器这样使用会进入一个死循环
    

    补充:
    5, 生成器必须要有明确的退出条件,为了不造成死循环. 所以慎用循环.

    def read_file():
        read_size = 10
        with open('test.txt','rb') as f:
            while True:
                text = f.read(read_size)
                if text:				#判断文件是否读取完毕
                    yield text		
                else:
                    return
    
    g = read_file()			
    while True:
        print(g.__next__())
    
    

    迭代器

    iterable(可迭代对象)可以直接作用与for循环的对象.可迭代对象分为:一,集合数据类型如:str字符串,list列表,dict字典,tuple元组,set集合等.二,生成器generator和带yield的函数.判断是否为iterable对象可以使用函数isinstance().
    在python中list等集合数据类型是非常占用内存的,通过使用iter()可以将一个可迭代对象变成一个迭代器.迭代器中不存储具体数据,只是保存了产生这种数据的逻辑对象.在使用时才产生需要的数据,可以大大节省空间.

    from collections import Iterator
    list = []
    for i in range(10):
        list.append(i)
    print(list,isinstance(list,Iterator))
    
    list_Iterator= iter(list)
    print(list_Iterator,isinstance(list_Iterator,Iterator))
    for i in list_Iterator:
        print(i)
    

    补充:
    1, 迭代器中并没有保存真正的数据,只有在我们去通过next方法去迭代器中取数据
    2, 迭代器中是按照一定的顺序输出所有数据,不能取指定的数据.

    装饰器

    装饰器(decorator)是一种函数的高级用法,主要是通过高阶函数和返回函数组合的方式,修饰其它函数.达到被修饰的函数代码不用修改,调用方式也不变的目的.主要作用就是给被修饰的函数添加功能.

    • 原函数不带参数
    #假如有这么三个函数,我们需要记录访问时间和函数名,但是又不能修改函数
    def home():
        print('index page')
    def bbs():
        print('bbs page')
    def news():
        print('news page')
    home()
    bbs()
    news()
    
    #加上装饰器后的效果
    import time
    
    log_list = []
    def user_log(func):     #将被装饰函数作为参数传入user_log这个装饰器
        def wrapper():		#触发执行装饰器的函数
            func()			#在装饰器内执行原函数
            log_time = time.strftime("%Y-%m-%d %H:%M:%S")	#装饰器内具体新代码
            page_name = func.__name__
            log_page = str(log_time+'  ->'+page_name)
            log_list.append(log_page)
        return wrapper		#将触发函数返回,一定不要加()执行符号
    
    @user_log
    def home():
        print('index page')
    
    @user_log
    def bbs():
        print('bbs page')
    
    @user_log
    def news():
        print('news page')
    
    home()
    bbs()
    news()
    print(log_list)
    
    • 带参数的函数
    计算函数运行时间的装饰器
    import time
    
    def time_consum(func):
        def wrapper(*args,**kwargs):
            start_time = time.time()
            func(*args,**kwargs)
            print('running',time.time()-start_time)
        return wrapper
    
    @time_consum
    def user_profile(username):
        time.sleep(3)
        print('welcome %s'%username)
    
    user_profile('sylar')
    
    • 装饰器带参数,
    #根据装饰器参数执行不同的功能
    import time
    log_list = []
    def change_type(ch_type='other'):
        def decorator(func):
            def wrapper(*args,**kwargs):
                if ch_type == 'tc':
                    start_time = time.time()
                    func(*args,**kwargs)
                    print('running',time.time()-start_time)
                else:
                    func()
                    print('other type code')
                    log_time = time.strftime("%Y-%m-%d %H:%M:%S")  # 装饰器内具体新代码
                    page_name = func.__name__
                    log_page = str(log_time + '  ->' + page_name)
                    log_list.append(log_page)
            return wrapper
        return decorator
    
    @change_type()
    def home():
        print('index page')
    
    @change_type('tc')
    def user_profile(username):
        time.sleep(3)
        print('welcome %s'%username)
    
    home()
    user_profile('sylar')
    print(log_list)
    

    递归函数

    在函数内部,调用了这个函数自己.就叫做递归函数

    #直接使用递归法求解斐波那契数量的第num个数字
    def fib(num):
        if num<2:
            return num
        return fib(num-1)+fib(num-2)
    
    for i in range(10):
        print(fib(i))
    

    补充递归函数必须要有一个明确的结束条件,python中支持最大递归次数1000

  • 相关阅读:
    opencv源码编译安装后使用时出现undefined reference cv::imwrite
    OPPO手机永久打开USB调试模式
    bash 顺序执行等待前一个脚本执行完成
    cpp
    多线程
    关于nvme下ubuntu无法识别硬盘的问题
    极限建站
    新生赛
    pc_mbed_fpga_communication
    color_sensor_mbed
  • 原文地址:https://www.cnblogs.com/ops-sylar/p/8183687.html
Copyright © 2011-2022 走看看