• 函数进阶2.0


    • 迭代器
    • 生成器
    • 装饰器

    迭代器

    可迭代对象

    可迭代(iter)是指支持iter的一个对象
    通俗地说可以循环的对象就是可循环的对象。

    可以用isinstance()判断一个对象是否为可迭代对象

    可迭代对象包括:字符串,列表,字典,元组等可以循环的对象

    >>> from collections import Iterable
    >>> isinstance([], Iterable)
    True
    >>>
    

    迭代器对象

    迭代器是指iter所返回的一个支持next(I)的对象

    可以被next()函数并不断返回下一个值直到抛出StopIteration异常的对象称为迭代器:Iteraor

    python中的迭代对象器:生成器,map、zip、filter

    for循环本质

    # 首先获得Iterator对象:
    it = iter([1, 2, 3, 4, 5])
    # 循环:
    while True:
        try:
            # 获得下一个值:
            x = next(it)
        except StopIteration:
            # 遇到StopIteration就退出循环
            break
    

    生成器

    Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果么不是立即产生结果。这也是生成器的主要好处

    定义生成器的两种方法:

    1、生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果。每个结果中间,挂起函数的状态,下次从他离开的地方继续执行。

    2、生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是构建一个结果列表

    比如把列表生成式中的[]改成()。

    >>> L = [x * x for x in range(10)]
    >>> L
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    >>> g = (x * x for x in range(10))
    >>> g
    <generator object <genexpr> at 0x1022ef630>
    

    斐波那契数列

    著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

    1, 1, 2, 3, 5, 8, 13, 21, 34, ...

    斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b)
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    fib(5) 
    
    

    仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

    也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

    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'
    data = fib(10)
    print(data)
    
    print(data.__next__())
    print(data.__next__())
    print("干点别的事")
    print(data.__next__())
    print(data.__next__())
    print(data.__next__())
    print(data.__next__())
    print(data.__next__())
    

    注意:生成器只能遍历一次

    总结:

    生成器和迭代器的本质区别是什么?什么场景用生成器?什么场景下用迭代器?

    生成器本质是一个迭代器。生成器不会一次性在内存中返回全部结果的列表,一次只返回一个结果。因此,生成器更加节省内存空间,比如处理一个100万个元素是列表,使用生成器并不会把内存撑爆。

    举个生活的例子,吃火锅的时候,使用生成器就相当于把吃火锅的时候刷肥牛。刷一块吃一块,使用迭代器,就相当于整盘肥牛倒进锅里,在捞起来吃。

    装饰器

    定义
    本质是函数:(装饰其他函数)就是为了其他函数添加附加功能

    原则

    1.不能修改被装饰的函数的源代码

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

    例子:

    你是一个视频网站的后端工程师,网站有以下几个模块

    def home():
        print("---首页----")
     
    def america():
        print("----欧美专区----")
     
    def japan():
        print("----日韩专区----")
     
    def henan():
        print("----河南专区----")
    

    新需求:“欧美”和“河南”板块需要付费,不能改变原代码和调用方式。

    user_status=False
    def login(func):  # 把要执行的模块从这里传进来
    
        def inner():  # 再定义一层函数
            _username = "alex"  # 假装这是DB里存的用户信息
            _password = "abc!23"  # 假装这是DB里存的用户信息
            global user_status
    
            if user_status == False:
                username = input("user:")
                password = input("pasword:")
    
                if username == _username and password == _password:
                    print("welcome login....")
                    user_status = True
                else:
                    print("wrong username or password!")
    
            if user_status == True:
                func()  # 看这里看这里,只要验证通过了,就调用相应功能
    
        return inner  # 用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
                       #america=inner
    
    @login  #america=login(america);login(america),america=inner  
    def america():
        # login() #执行前加上验证
        print("----欧美专区----")
    
    
    def japan():
        print("----日韩专区----")
    
    
    @login
    def henan():
        # login() #执行前加上验证
        print("----河南专区----")
    
    def home():
        print('--首页--')
    
    home()
    america()
    henan()
    

    往河南板块传个参数,结果出错了。因为....

    调用henan时,其实是相当于调用的login。henan第一次调用时henan = login(henan), login就返回了inner的内存地址,第2次用户自己调用henan("3p"),实际上相当于调用的时inner,但inner定义时并没有设置参数,所以报错。

    升级版:

    user_status = False #用户登录了就把这个改成True
    
    def login(auth_type): #把要执行的模块从这里传进来
        def auth(func):
            def inner(*args,**kwargs):#再定义一层函数
                if auth_type == "qq":
                    _username = "alex" #假装这是DB里存的用户信息
                    _password = "abc!23" #假装这是DB里存的用户信息
                    global user_status
    
                    if user_status == False:
                        username = input("user:")
                        password = input("pasword:")
    
                        if username == _username and password == _password:
                            print("welcome login....")
                            user_status = True
                        else:
                            print("wrong username or password!")
    
                    if user_status == True:
                        return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
                else:
                    print("only support qq ")
            return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
    
        return auth
    
    def home():
        print("---首页----")
    
    @login('qq')
    def america():
        #login() #执行前加上验证
        print("----欧美专区----")
    
    def japan():
        print("----日韩专区----")
    
    @login('weibo')
    def henan(style):
        '''
        :param style: 喜欢看什么类型的,就传进来
        :return:
        '''
        #login() #执行前加上验证
        print("----河南专区----")
    
    home()
    # america = login(america) #你在这里相当于把america这个函数替换了
    #henan = login(henan)
    
    # #那用户调用时依然写
    america()
    
    # henan("3p")
    

    练习

    1、用装饰器实现计算函数运行时间

    import time
    
    def cal(func):
        def wraps():
            start_time = time.time()
            res = func()
            end_time = time.time()
            print("time:", end_time - start_time)
            return res
        return wraps
        
     
    @cal
    def f1():
        print("in the f1")
        time.sleep(1)
       
       
    @cal
    def f2():
        print("in the f2")
        time.sleep(2)
    
    
    @cal
    def f3():
        print("in the f3")
        time.sleep(3)
        
    f1()
    f2()
    f3()
    

    2、打印10以下斐波那契数列

    姿势1

    def fib(max):
    	a, b, n = 0,1,0
    	while b < max:	
    		print(b)
    		a,b = b, a+b
    		n += 1
    
    	return
    
    
    fib(10)
    

    姿势2

    fibs = [0,1]
    for i in range(10):
    	fibs.append(fibs[-2]+fibs[-1])
    
    for i in fibs:
    	if i <= 10:
    		print(i)
    
  • 相关阅读:
    Scanner和BufferedReader
    java annotation
    java获取短uuid
    定时任务线程
    sql 查询最近30分钟或者自定义时间数据
    查看base64编码图片
    oracle 的PACKAGE恢复过程
    Oracle BFILE备忘
    读取Spring的配置文件applicationContext.xml的5种方法
    解决eclipse ctrl+鼠标左键不能用
  • 原文地址:https://www.cnblogs.com/Jason-lin/p/8326210.html
Copyright © 2020-2023  润新知