zoukankan      html  css  js  c++  java
  • 函数进阶

    内容摘要:本文主要是介绍闭包,装饰器,装饰器的应用与进阶,迭代器与生成器,列表推导式以及生成器表达式内容。

    1.闭包

    '''
    整体说明:
    01 动态参数:万能参数,*args **kwargs
        (1)在函数定义时:* ** 代表聚合
        (2)在函数调用时:* ** 代表打散
    
    02 函数名的运用
        (1)函数名可以作为变量。
        (2)函数名可以作为函数的参数。
        (3)函数名可以作为容器类类型的元素。(容器类型的数据包括字典、集合、列表(有序)、元素)
        (4)函数名可以作为函数的返回值。
    03 闭包
        (1)闭包是嵌套在函数中的。
        (2)闭包是内层函数对外层函数的变量(非全局变量)的引用(改变)。
        (3)闭包需要将其作为一个对象返回,而且必须逐层返回直至最外层的函数的返回值。
        (4)闭包的作用:python遇到闭包,产生一个空间,这个空间不会随着函数的结束而消失。(普通的非闭包的函数,变量的空间会随着函数的结束而消失)
        
    '''
    
    # 01  动态参数:万能参数,*args **kwargs,在函数的定义时:* ** 代表聚合。
    def func(*args, **kwargs):
        print(args)   # (1, 2, 3, 'alex')
        print(kwargs)  # {'name': '太白', 'age': 25}
    
    func(1, 2, 3, 'alex', name='太白', age=25)
    
    # 02 动态参数:万能参数,*args **kwargs,在函数的调用时:* ** 代表打散
    
    # *的使用
    def func(*args, **kwargs):
        print(args)  # (1, 2, 3, 'alex', '太白')
        print(kwargs)  # {}
    
    
    func(*[1, 2, 3, ], *['alex', '太白'])
    
    
    # **的使用
    def func(*args, **kwargs):
        print(args)  # ()
        print(kwargs)  # {'name': 'alex', 'age': 73}
    
    func(**{'name': 'alex', 'age': 73})
    # func(**{1: 'alex', 'age': 73})  # 会报错,因为关键字要求必须是字符串
    
    # 03 函数名的应用
    # (1) 函数名可以作为变量
    def func1():
        print(1111)
    
    
    ret = func1
    ret()
    输出结果:1111
    
    # (2) 函数名可以作为函数的参数
    def func2():
        print(666)
    
    
    def func3(x):
        x()
    
    
    func3(func2)
    # 输出结果:6666
    
    # (3) 函数名可以作为容器类的元素
    def func1():
        print(666)
    
    
    def func2():
        print(777)
    
    
    def func3():
        print(888)
    
    
    l1 = [func1, func2, func3]
    for i in l1:
        i()
    # 输出结果: 666 777 888
    
    # (4) 函数名可以作为函数的返回值
    def func1():
        print(666)
    
    
    def func2(x):
        print(888)
        return x
    
    
    ret = func2(func1)  # 遇到赋值预算先计算赋值运算作出的内容,本赋值是先执行func2函数, 并且将func1作为返回值返回给我ret
    ret()  # 由于func1的函数名赋值给ret,所以ret具有func1作为函数的所有特性,即函数名()-是函数的调用者,所以执行func1函数
    # 输出结果:888  666
    
    # 04 闭包
    
    # (1) 闭包的举例:
    
    # 以下是闭包
    def wrapper():
        name = '太白'
        def inner():
            print(name)
        return inner
    
    # 以下是闭包:外层函数的变量定义相当于name = n1,是个局部变量所以满足条件,因此是闭包。
    def wrapper(name):
        def inner():
            print(name)
        return inner
    n1 = 'wusir'
    wrapper(n1)
    
    # 以下不是闭包:因为内层函数调用的变量是全局变量,而不是外层函数的局部变量,未满足条件所以不是。
    name = 'alex'
    def wrapper():
        def inner():
            print(name)
        return inner
    
    # (2)闭包的作用
    
    # 非闭包函数 随着函数的结束临时空间关闭,即变量的赋值会清空
    def func1(s1):
        n = 1
        n += s1
        print(n)
    
    
    func1(5)
    func1(5)
    func1(5)
    func1(5)
    # 输出结果: 6 6 6 6
    
    # 闭包的机制:python遇到闭包,产生一个空间,这个空间不会随着函数的结束而消失。
    def wrapper(s1):
        n = 1
        def inner():
            nonlocal n  # 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。
            n += s1
            print(n)
        return inner
    
    ret = wrapper(5)
    ret()
    ret()
    ret()
    ret()
    # 输出结果:6 11 16 21

    2.装饰器

    '''
    整体说明:
    01 装饰器说明
        (1) 装饰器的本质是闭包。
        (2) 装饰器是在不改变原函数的内部函数体以及调用方式(也包括调用次数)的情况下,给函数增加了额外的功能:比如登录、注册、打印日志、函数效率等等。
    02 标准装饰器:手写的标准装饰器总共分5步。
    '''
    # 01 标准装饰器
    def wrapper(f):
        def inner(*args, **kwargs):
            print('执行之前', 555)  # 在执行前可以编写新增的功能代码,比如登录验证、注册、打印日志等。
            ret = f(*args, **kwargs)  # 该处是装饰器核心,用于调用函数使用
            print('执行之后', 666)  # 在执行前可以编写新增的功能代码,比如登录验证、注册、打印日志等。
            return ret
    
        return inner
    
    # 02 装饰器的使用方式
    
    # 0201 初级的引用方式(未优化版本)
    
    # 引用时间模块
    import time
    
    def func1():
        time.sleep(0.6)
        print('来了,老弟')
    
    
    def func2():
        time.sleep(0.6)
        print('来le')
    
    
    def func3():
        time.sleep(0.6)
        print('')
    
    
    # 定义一个测量函数执行执行效率的装饰器
    
    def func1():
        time.sleep(0.6)
        print('来了,老弟')
    
    def timmer(f): # f = func1 函数名的内存地址
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行时间是%s' % (end_time-start_time))
        return inner
    func1 = timmer(func1)  # 首先执行赋值运算,将返回值inner函数名的内存地址赋值给新变量func1,新变量func1具有inner作为函数名的所有特性
    func1()  # inner()
    '''
    以上函数具体执行过程说明:
    1.先计算赋值运算左侧的:timmer(func1)
    2.执行timmer函数,并且将func1传递给f
    3.inner函数不执行,将inner函数名返回给timmer(func1)
    4.在内存中重新创建一个变量叫做func1,此时func1 = inner
    5.执行inner()执行inner函数,执行f()
    '''
    
    # 0202 使用python提供的语法糖'@'(优化方法)
    # 引用时间模块
    import time
    
    # 定义装饰器
    def timmer(f):  # f = func1 函数的内存地址
        def inner():
            start_time = time.time()
            f()
            end_time = time.time()
            print('此函数的执行时间是%s' % (end_time - start_time))
    
        return inner
    
    '''
    @timmer的作用
    1.@timmer相当于func1 = timmer(func1)
    2.@timmer需要写在函数定义前,这可以保证函数在被调用时即执行装饰器的功能,无论多少次调用只要写一次即可。
    3.@timmer可以把定义的函数看做为一行来进行使用,实际上当执行到语法糖的时候,寻找最近的函数,完成1中的等式。
    '''
    
    @timmer  # 切记将语法糖写在函数定义之前
    def func1():
        time.sleep(0.6)
        print('来了,老弟')
    
    func1()  # inner()
    
    @timmer
    def func2():
        time.sleep(0.6)
        print('来le')
    func2()
    
    # 03 被装饰的函数带有参数
    import time
    def timmer(f):  # f = func1 函数的内存地址
        def inner(*args, **kwargs):
            start_time = time.time()
            f(*args, **kwargs)  # 真正执行函数func1的一句
            end_time = time.time()
            print('此函数的执行时间是%s' % (end_time - start_time))
    
        return inner
    
    
    @timmer  # func1 = timmer(func1)
    def func1(a):
        time.sleep(0.6)
        print('来了,%s' % (a))
    
    
    func1('alex')
    
    # 输出结果: 来了,alex  此函数的执行时间是0.6000347137451172
    
    # 04 被装饰函数有返回值
    import time
    def timmer(f):  # f = func1 函数的内存地址
        def inner(*args, **kwargs):
            start_time = time.time()
            ret = f(*args, **kwargs)  # 真正调用func1函数
            end_time = time.time()
            print('此函数的执行时间是%s' % (end_time - start_time))
            return ret
        return inner
    @timmer  # func1 = timmer(func1)
    def func1(a):
        time.sleep(0.6)
        print('来了,%s' % (a))
        return 666
    print(func1('alex'))  # print(inner('alex'))
    
    # 输出结果:来了,alex  此函数的执行时间是0.600034236907959  666

    3.装饰器的应用

    # 登录认证的应用(示例,具体完整内容详见作业4博客园的登录验证)
    
    login_status = {
        'username': None,
        'status': False,
    }
    
    
    def login(f):
        def inner(*args, **kwargs):
            if login_status['status']:
                ret = f(*args, **kwargs)
                return ret
            else:
                print('请先登录')
                username = input('请输入用户名').strip()
                password = input('请输入密码').strip()
                if username == '二狗' and password == '123':
                    login_status['username'] = username
                    login_status['status'] = True
                    ret = f(*args, **kwargs)
                    return ret
        
        return inner
    
    
    @login
    def article():
        print('欢迎访问文章页面')
    
    
    @login
    def dariy():
        print('欢迎访问日记页面')
    
    
    @login
    def comment():
        print('欢迎访问评论页面')
    
    
    dic = {
        1: login,
        2: article,
        3: dariy,
        4: comment,
    }
    
    while 1:
        print('''
        欢迎来到博客园首页:
        1,登录
        2,文章页面
        3,日记页面
        4,评论页面
        ''')
        num = input('请输入数字:').strip()
        dic[int(num)]()

    4.装饰器的进阶

    '''
    整体说明:
    01 带参数的装饰器
        (1)应用场景1:对500个函数加上装饰器,之后去掉,之后再加上。
        (2)带参数的装饰器相当于增加一个开关,可以让装饰器生效与失效。
    02 多个装饰器装饰一个函数
    '''
    
    # 01 带参数的装饰器的的标准形式:
    def login(a, b):
        print(a, b)
        def wrapper(f):
            def inner(*args, **kwargs):
                ret = f(*args, **kwargs)
                return ret
            return inner
        return wrapper
    
    @login(1,2)
    def func1():
        print(111)
    
    func1()
    
    # 02 带参装饰器的举例
    login_status = {
        'username': None,
        'status': False,
    }
    
    def login(a):
        def wrapper(f):
            def inner(*args, **kwargs):
                if a:  # 判断装饰器是否生效,如果flag = True则执行装饰器,否则则不执行装饰器
                    if login_status['status']:
                        ret = f(*args, **kwargs)
                        return ret
                    else:
                        print('请先登录')
                        username = input('请输入用户名').strip()
                        password = input('请输入密码').strip()
                        if username == '二狗' and password == '123':
                            login_status['username'] = username
                            login_status['status'] = True
                            ret = f(*args, **kwargs)
                            return ret
                else:
                    ret = f(*args, **kwargs)
                    return ret
            return inner
        return wrapper
    
    flag = False  # 设置开关,定义装饰器生效和失效
    
    @login(flag)
    def func1():
        print(111)
    @login(flag)
    def func2():
        print(12)
    @login(flag)
    def func3():
        print(131)
    
    func1()
    
    
    
    login_status = {
        'username': None,
        'status': False,
    }
    
    
    def login(a):
        def wrapper(f):
            def inner(*args, **kwargs):
                if login_status['status']:
                    ret = f(*args, **kwargs)
                    return ret
                else:
                    print('请先登录')
                    '''根据a 京东,天猫 去验证不同密码'''
                    username = input('请输入用户名').strip()
                    password = input('请输入密码').strip()
                    if username == '二狗' and password == '123':
                        login_status['username'] = username
                        login_status['status'] = True
                        ret = f(*args, **kwargs)
                        return ret
    
            return inner
        return wrapper
    
    
    @login('京东')
    def jd():
        print('欢迎访问文章页面')
    
    
    @login('京东')
    def jdmarkte():
        print('欢迎访问日记页面')
    
    
    @login('天猫')
    def TM():
        print('欢迎访问评论页面')
    
    @login('天猫')
    def TMmarke():
        print('欢迎访问评论页面')
    
    # 02 多个装饰器装饰一个函数
    def wrapper1(func):  # func = 函数名f
        def inner1():
            print('wrapper1 ,before func')  # 2
            func()  # 函数f
            print('wrapper1 ,after func')  # 4
    
        return inner1
    
    
    def wrapper2(func):  # func = inner1
        def inner2():
            print('wrapper2 ,before func')  # 1
            func()  # inner1()
            print('wrapper2 ,after func')  # 5
    
        return inner2
    
    
    @wrapper2  # f = wrapper2(f) 里面的f 是inner1 外面的f 是inner2
    @wrapper1  # f = wrapper1(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
    '''
    
    '''
    执行顺序说明:(可以简答理解为先自上而下之后再自下而上)
    1.首先,遵循自上而下的原则,依次开辟wrapper1和wrapper2的空间。
    2.执行到装饰器后,依据就近原则,先执行装饰器wrapper1,即f = wrapper1(f),之后执行装饰器wrapper2,即f = wrapper1(f)
      此时,f = wrapper1(f) 里面的f是函数名f  外面的f是 inner1,f = wrapper2(f) 里面的f 是inner1 外面的f 是inner2。
    3.执行inner2函数(inner1是函数inner2的变量),首先先打印“wrapper2 ,before func”,之后将变量inner1赋值给f。
    4.执行inner1函数(f为函数inner1的变量),首先打印‘wrapper1 ,before func’,之后执行f(),即打印‘in f’,执行完成后打印
      'wrapper1 ,after func',函数inner1执行完成,即wrapper2中的func()函数执行完成。
    5.最后执行wrapper2种的打印语句,将‘wrapper2 ,after func’打印输出。
    '''

    5.迭代器与生成器

    '''
    整体说明:
    01 可迭代对象:内部含有‘__iter__’方法的数据就是可迭代对象,包括list str tuple set dict range() 文件句柄
    02 迭代器:内部含有‘__iter__’方法的并且含有‘__next__’方法的就是迭代器
    03 可迭代对象 ----> 迭代器(转化)
    04 迭代器的作用:
        (1)非常非常的节省内存
        (2)满足惰性机制
        (3)一条路走到黑(可以理解为类似于指针,下次读取时从上去读取结束时的位置开始读)
    05 利用while循环模拟for循环机制。
        (1)将可迭代对象转化成迭代器
        (2)利用next 进行取值
        (3) 利用异常处理终止循环。
    06 生成器:自己用python代码写的迭代器 本质就是迭代器
        (1)函数式写法:
            a)只要函数中出现yield,那么 他就不是函数了,他是生成器函数。
            b)yield和return的区别
                i)return 结束函数 给函数返回值
                ii)yield 不会结束生成器函数,next 对应一个yield进行取值
        (2)生成器表达式
    '''
    
    # 01 可迭代对象
    # 判断方法
    s1 = '二狗的周末生活'
    print(dir(s1))  # 用dir可以打印所有的方法
    print('__iter__' in dir(s1))  # 判断是否包含_iter_方法,如果包含结果是True,如果不包含结果为False
    
    # 02 迭代器
    # 判断方法
    f1 = open('regsiter', encoding='utf-8')
    print('__iter__' in dir(f1))  # 判断是否包含_iter_方法,如果包含结果是True,如果不包含结果为False
    print('__next__' in dir(f1))   # 判断是否包含_next_方法,如果包含结果是True,如果不包含结果为False
    f1.close()
    
    # 03 可迭代对象->迭代器
    l1 = [1, 2, 3, 'alex']
    iter1 = iter(l1)  # l1.__iter__(),将可迭代对象转化为迭代器
    print(iter1)   # 打印出的一个元素的地址<list_iterator object at 0x00000000021DE278>
    print(iter1.__next__())
    print(iter1.__next__())
    print(iter1.__next__())
    print(iter1.__next__())
    # for循环的方式依次输出
    for i in iter1:
        print(i)
    
    # 04  利用while循环模拟for循环 的机制。
    
    l1 = [1, 2, 3, 'alex']
    iter1 = l1.__iter__()
    while 1:
        try:
            print(iter1.__next__())
        except StopIteration:  # except是用来异常处理的作用
            break
    
    # 05 生成器
    # 0501 函数式写法 构建生成器
    def func1():
        # print(111)
        # print(222)
        yield 3
        yield 4
        yield 5
        yield 6
        yield 7
    
    
    g = func1()  # 生成器对象
    print(g)   # 打印出生成器的地址
    print(g.__next__())  # print(next(g)),一个next 对应一个 yield
    print(g.__next__())
    print(g.__next__())
    print(g.__next__())
    
    # 0502 生成器举例
    
    def cloth():
        for i in range(1,201):
            print('老男孩老年体恤%s号' % (i))
    cloth()
    
    
    def cloth1():
        for i in range(1,201):
            yield '老男孩老年体恤%s号' % (i)
    
    g = cloth1()
    
    for i in range(5):
        print(g.__next__())
    
    for i in range(195):
        print(g.__next__())

    6.列表推导式与生成器表达式

    '''
    整体说明:
    01 列表推导式
        (1)凡是用列表推导式能构建的数据,python代码都可以构建,列表推导式不能构建的数据,python代码亦可以可以构建。
        (2)两种模式:
            a)循环模式: [变量(加工后的变量) for 变量 in iterable]
            b)筛选模式:[变量(加工后的变量) for 变量 in iterable if 条件]
    02 生成器表达式:
        (1)两种模式:
            a)循环模式: (变量(加工后的变量) for 变量 in iterable)
            b)筛选模式:(变量(加工后的变量) for 变量 in iterable if 条件)
        (2)生成器表达式与列表推导式用() 括起来,其他规则与列表推导式一致。
    03 列表推导式,生成器表达式的优缺点。
        (1)优点:构造简单,一行完成
        (2)缺点:
            a)不能排错
            b)不能构建复杂的数据结构
    
    '''
    
    # 01 循环模式: [变量(加工后的变量) for 变量 in iterable]
    # 举例:用列表推导式:构建一个列表:['python1期', 'python2期'....,'python24期']
    print(['python%s期' % i for i in range(1, 25)])
    
    # 02 筛选模式 [变量(加工后的变量) for 变量 in iterable if 条件]
    # 举例:
    # 10以内所有数的平方。
    print([i * i for i in range(1, 11)])
    # 30以内能被3整除的数的平方。
    print([i ** 2 for i in range(1, 31) if i % 3 == 0])
    # l1 = ['alex', 'taibai', 'wusir', 're', 'ab'],过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母。
    print([i.upper() for i in l1 if len(i) > 3])
  • 相关阅读:
    Linux 安装 PostgreSQL
    【Linux】ZeroMQ 在 centos下的安装
    Celery
    Django学习之完成数据库主从复制、读写分离和一主多从情况下的使用办法
    python异步编程之asyncio(百万并发)
    Python正则表达式中的re.S,re.M,re.I的作用
    云开发 :云原生(Cloud Native)
    极简Unity调用Android方法
    UnityShader快速上手指南(四)
    UnityShader快速上手指南(三)
  • 原文地址:https://www.cnblogs.com/mayugang/p/9907594.html
Copyright © 2011-2022 走看看