zoukankan      html  css  js  c++  java
  • python笔记3 闭包 装饰器 迭代器 生成器 内置函数 初识递归 列表推导式 字典推导式

    闭包

    1, 闭包是嵌套在函数中的

    2, 闭包是内层函数对外层函数的变量(非全局变量)的引用(改变)

    3,闭包需要将其作为一个对象返回,而且必须逐层返回,直至最外层函数的返回值

    闭包例子:

    def a1():
        name = 'wk'
        def a2():
            print(name)
        return a2

     闭包函数的作用

    非闭包函数:随着函数的结束临时空间关闭

    def func1(s):
        n = 1
        n += s
        print(n)
    func1(3)
    func1(3)             #每次函数结束临时空间关闭
    func1(3)
    
    4
    4
    4

    闭包函数 :不会随函数结束释放内存空间

    def func1(s):
        n = 1
        def cc():
            nonlocal n
            n += s
            print(n)
        return cc
    func1(2)()
    func1(2)()
    func1(2)()
    cd = func1(2)   #cd = func1(2) 既将cc = cd,接下来的cd一直在跑的是cc()函数,而非从上往下依次跑,且不会随函数结束释放内存空间
    cd()
    cd()
    cd()
    
    3
    3
    3
    3
    5
    7

    装饰器

    装饰器:给函数增加一个新功能:

    例:需要写一个功能,测试函数的执行效率

    import time                   #需要测试的函数
    def aa():
        print(111)
        time.sleep(1)
    aa()

    low方法: 

    import time                     #重复造轮子,测试函数的效率 必须得复制代码,
    def aa():
        start = time.time()
        print(111)
        time.sleep(1)
        end = time.time()
        print('执行了%s秒' %(start - end))
    aa()
    
    111
    执行了-1.0003249645233154秒

    增加需求对N个函数都要操作:

    import time                         #改变了函数的调用方式
    def aa():  
        print(111)
        time.sleep(1)
    
    def cc(xx):                            #将被测试的函数名当做参数传入
        start = time.time()
        xx()
        end = time.time()
        print('执行了%s秒' %(start - end))
    
    cc(aa)                                 #执行cc即可测试N个函数
    
    111
    执行了-1.000324010848999秒

    用最少的代码,解决调用方式一致性的问题(不改变源代码的调用方法)。

    import time                        
    def aa():
        print(111)
        time.sleep(1)
    
    def cc(xx):
        def inner():
            start = time.time()
            xx()
            end = time.time()
            print('执行了%s秒' %(start - end))
        return inner
    aa = cc(aa)
    aa()
      
    111
    执行了-1.0004630088806152秒

    最终基础版 python提供一个机制,优化,语法糖 @

    import time                             
    def cc(xx):
        def inner():
            start = time.time()
            xx()
            end = time.time()
            print('执行了%s秒' %(start - end))
        return inner
    
    @cc                    #  @cc 为 aa = cc(aa)
    def aa():
        print(111)
        time.sleep(1)
    aa()
    
    111
    执行了-1.0007429122924805秒

    装饰器本质其实闭包,装饰器在不改变原函数的内部函数体以及调用方式的前提下,给函数增加了额外的功能:登录,注册,打印日志,函数效率等等。

    装饰器传参

    def func(f1):
        def aa(x):
            s1 = time.time()
            f1(x)
            print(time.time() - s1)
        return aa
    
    @func                 
    def dd(x):
        time.sleep(2)
        print("来了老弟 %s" %(x))
    dd(111)
    来了老弟
    111 2.0003223419189453

    装饰器多个参数传参

    import time
    def func(f1):
        def aa(*args, **kwargs):
            s1 = time.time()
            f1(*args, **kwargs)
            print(time.time() - s1)
        return aa
    
    @func
    def dd(a, b, c):
        time.sleep(2)
        print("来%s 老弟 %s %s" %(a,b,c))
    
    dd('wk', 25, 'xixi')

    来wk 老弟 25 xixi
    2.000187635421753

    被装饰的函数有返回值

    import time
    def func(f1):
        def aa(*args, **kwargs):
            s1 = time.time()
            s2 = f1(*args, **kwargs)
            print(time.time() - s1)
            return s2
        return aa
    @func
    def dd(a, b, c):
        time.sleep(2)
        print("来%s 老弟 %s %s" %(a,b,c))
        return 111
    print(dd('wk', 25, 'xixi'))

      来wk 老弟 25 xixi
      2.000335693359375
      111

    简单的博客园登陆

    login_status = {
        'username': None,
        'status': False,
    }
    def login(x):
        def aa():
            if login_status['status']:
                x()
    
            else:
                user = input("请输入用户名")
                passwd = input('请输入密码')
                if user == 'wk' and passwd == '123456':
                    print('登陆成功')
                    login_status['username'] = user
                    login_status['status']= True
                    x()
        return aa
    @login
    def wenzhang():
        print('欢迎访问文章页面')
    @login
    def riji():
        print('欢迎访问日记界面')
    @login
    def pinglun():
        print('欢迎来到评论界面')
    dic = {
        1: login,
        2: wenzhang,
        3: riji,
        4: pinglun,
    }
    while 1:
        print('''
        欢迎来到博客园首页:
        1,登录
        2.文章页面
        3.日记页面
        4.评论页面   
        ''')
        num = input('请输入数字')
        dic[int(num)]()

    装饰及进阶,带参数的装饰器

    def aa(a,b):
        def bb(x):
            def cc():
                x()
                print(a,b)
            return cc
        return bb
    @aa(1,2)            #aa(1,2)获得 bb的返回值,aa()= bb  @bb为装饰器 
    def dd():
        print(111)
    dd()
    
    111
    1 2

    多个装饰器装饰一个参数

    def aa1(func):    # func = 函数名f
        def inner1():
            print('wrapper1 ,before func')  # 2
            func()  # 函数f
            print('wrapper1 ,after func')  # 4
        return inner1
    
    def aa2(func):    # func = inner1
        def inner2():
            print('wrapper2 ,before func')  # 1
            func()  # inner1()
            print('wrapper2 ,after func')  # 5
        return inner2
    
    @aa2  #f = aa2(f.)  f. = infner1(f)
    @aa1  # f = aa1(f) 里面的f是函数名f  外面的f是 inner1
    def f():
        print('in f')  # 3
    f()  # inner2

      wrapper2 ,before func
      wrapper1 ,before func
      in f
      wrapper1 ,after func
      wrapper2 ,after func

    多个装饰器就近执行先执行@aa1在执行@aa2 ,@aa1为 f = aa1(f)= inner1并将f作为参数传进去,此时inner1里的f = print('in f').

    在执行@aa2  @aa为 f =aa2(f) = inner2 并将f 作为参数传进去,此时inner2里的 f = inner1

    因此在执行时,f = inner2  输出步骤为:

    1. 先执行inner2的 ”wrapper2 ,before func“ 

    2执行f()    f()=inner1()   = "wrapper1 ,before func",“in f”,"wrapper1 ,after func"    (inner1里的f为print('in f')

    3.执行inner2的“wrapper2 ,after func”

    迭代器

    可迭代对象

    可迭代对象: 内部含有"__iter__"方法的数据就是可迭代对象,像list str tuple set dict range() 文件句柄 都是可迭代对象

    s1 = '嘣沙卡拉卡'
    print('__iter__' in dir(s1))          #判断s1是否是可迭代对象
    True

    迭代器

    内部含有"__iter__"方法的并且含有"__next__"方法的就是迭代器 (列表是可迭代对象却不是迭代器)

    f1 = open('regsiter', encoding='utf-8')
    print('__iter__' in dir(f1))
    print('__next__' in dir(f1))
    
    True
    True

    迭代器:next -->一次取一个值

    l1 = [1, 2, 3, 4]
    l2 = iter(l1)
    print(l2.__next__())
    print(l2.__next__())
    print(l2.__next__())
    print(l2.__next__())
    
    1
    2
    3
    4

    列表是可迭代对象却不是迭代器

    lst = [1,2,3]
    print(dir(lst))
    
    ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__',
    '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__',
    '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__',
    '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__',
    '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert',
    'pop', 'remove', 'reverse', 'sort'] #迭代器里没有 __next__方法,因此不是迭代器 进程已结束,退出代码 0
    lst = [1,2,3]
    t1 = lst.__iter__()       #此时t1就是一个迭代器
    print(t1.__next__())      #迭代t1用__next__方法 得到1
    
    1

    迭代器:

      1.可以非常非常节省内存

      2.满足惰性机制.

      3.一条路走到黑.

    利用while循环模拟for循环的机制.

    1.将可迭代对象转化为迭代器

    2.利用next进行取值

    3.利用异常处理终止循环

    l1 = [1, 2, 3, 4]
    l2 = iter(l1)
    while 1:
        try:
            print(l2.__next__())
        except StopIteration:
            break
    
    1
    2
    3
    4

    生成器

    生成器内部保存的是代码而不是数据

    函数式写法构建生成成器

    def cc1():
        yield 1      #只要函数中出现yield,那么他就不是函数了,他是生成器函数.
        yield 2     
        yield 3
        yield 4
    c1 = cc1()        #生成器对象
    print(c1.__next__())
    print(c1.__next__())
    print(c1.__next__())
    print(c1.__next__())
    
    1
    2
    3
    4

    return和yield 的区别

    return结束函数,给函数返回值

    yield 不会结束生成器函数,next对应一个yield进行取值

    def aa():                       #生成器的好处,按需去取,需要多少取多少,并记录取到哪了
        for i in range(40):
            yield '这是数字%s' % (i)
    a1 = aa()
    for i in range(5):
        print(a1.__next__())
    
    这是数字0
    这是数字1
    这是数字2
    这是数字3
    这是数字4

    send()也可以像__next__()一样执行生成器中的代码,都是执行到下一个yield

    send()可以给上一个yield传值  ,第一次运行没有yield的传值,所以只能用于next之后.

    def aa():
        print('11111')
        a = yield '222'
        print(a)
        print('3333')
        b = yield '4444'
        print(b)
    gen = aa()
    print(gen.__next__())
    print(gen.send('555'))       #遇到send 可将上个yield的值改为send里的参数, 并执行到下一个yield结束
    
    11111
    222
    555
    3333
    4444

    yield from 

    def aa():
        yield from [1, 2, 3, 4]
        yield from [5, 6, 7, 8]
    cc = aa()
    print(cc.__next__())
    print(cc.__next__())
    print(cc.__next__())
    print(cc.__next__())
    print(cc.__next__())
    
    1
    2
    3
    4
    5

    列表推导式

    生成一个1到100的列表:

    l1 = [i for i in range(1, 101)]
    print(l1)
    循环模式 [变量(加工后的变量) for 变量 in iterable]
    筛选模式 [变量(加工后的变量) for 变量 in iterable if 条件]

    循环模式:

    l1 = ['python%s期' %(i) for i in range(1, 25)]
    print(l1)
    ['python1期', 'python2期', 'python3期', 'python4期', 'python5期', 'python6期', 'python7期', 'python8期', 'python9期', 'python10期', 'python11期', 'python12期', 'python13期', 'python14期', 'python15期', 'python16期', 'python17期', 'python18期', 'python19期', 'python20期', 'python21期', 'python22期', 'python23期', 'python24期']

    筛选模式

    l2 = [i**2 for i in range(1,31) if i % 3 == 0]
    print(l2)
    [9, 36, 81, 144, 225, 324, 441, 576, 729, 900]

    生成器表达式:  (i*i for i in range(1, 11))  用()括起来,其他规则和列表推导式一样

    c1 = (i*i for i in range(1, 11))
    for i in c1:
        print(i)
    1
    4
    9
    16
    25
    36
    49
    64
    81
    100

    列表推导式,生成器表达式:

    优点:构造简单,一行完事

    缺点:1.不能排错

       2.不能构建复杂的数据

     字典推导式

    lst = ['持国天王','广目天王','多闻天王','增长天王']
    dic = {i:lst[i] for i in range(len(lst))}
    print(dic)
    
    {0: '持国天王', 1: '广目天王', 2: '多闻天王', 3: '增长天王'}

    集合推导式

    s = {i for i in range(6)}

     

    
    
  • 相关阅读:
    SpringBoot--日期格式化
    SpringBoot--使用redis实现分布式限流
    SpringBoot--集成Shiro
    xxl-job搭建、部署、SpringBoot集成xxl-job
    SpringBoot--使用socket搭建聊天室
    SpringBoot--数据库管理与迁移(LiquiBase)
    SpringBoot--防止重复提交(锁机制---本地锁、分布式锁)
    Springboot--元注解及自定义注解(表单验证)
    java类对象的初始化顺序
    java23种设计模式(三)单例模式
  • 原文地址:https://www.cnblogs.com/ywrj/p/10116264.html
Copyright © 2011-2022 走看看