zoukankan      html  css  js  c++  java
  • 函数-----函数进阶(闭包、无参装饰器、有参装饰器、迭代器、生成器)

    一、名称空间

    顾名思义就是存放名字的地方;举例:若变量X=1,1存放在内存中,是存放名字X与1绑定关系的地方。

    名称空间有三种:

    1.locals:函数内的名称空间,包括局部变量和形参

    2.globals:全局变量,函数定义锁在模块的名字空间

    3.builtins: 内置模块的名字空间

    二、作用于的查找顺序

    LEGB顺序

    locals--->enclosing(外部嵌套函数的名称空间)--->globals--->builtins

    三、闭包

    即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。而且,这些函数可以访问他们所在的外部函数中声明的所有局部变量、参数。当其中一个这样的内部函数在包含他们的外部函数之外被调用时,就会形成闭包。

    闭包的意义:返回的函数对象,不仅仅是一个函数对象,在函数对象外还包含了一层作用于,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。

    def func():
        n = 10
        def func2():
            print('func2:',n)
        return func2
    
    f = func()
    print(f)
    f()
    
    >>>><function func.<locals>.func2 at 0x000001F9C4B1B9D8>
    >>>>func2: 10

    为函数传参的两种方式:

    方式一:直接把函数需要的参数定义成形参

    方式二:利用闭包函数传参

    复制代码
    def func():
        x = 4
        def func2():
            print(x)
        return func2
    res = func()
    print(res)
    res()

    四、装饰器

       定义:定义一个工具,该工具是用来装饰其他函数的,来增加额外功能的。

      为什么要用装饰器:在不修改被装饰器源代码对象以及调用方式的前提下,为被装饰对象添加新功能。

    开放封闭原则:对拓展功能是开放的;对修改源代码是封闭的。

    import time
    
    def index(x,y,z):
        time.sleep(3)
        print('index%s %s %s' %(x,y,z))
        return 666
    # print(index)-------<function index at 0x000001A2AD783E18>
    
    def outter(func1):
        # func = index的内存地址
        def wrapper(*args,**kwargs):
            start = time.time()
            res = func1(*args,**kwargs)  # index的内存地址
            stop = time.time()
            print(stop - start)
            return res
        return wrapper
    index = outter(index)  # outter的内存地址
    # print(index)-----<function outter.<locals>.wrapper at 0x000001A2AF67BA60>
    res = index(3,5,6,)
    print('返回值----',res)
    
    # 结果
    # >>>  index3 5 6
    # >>>  3.000042200088501
    # >>>  返回值---- 666

    语法糖:当需要同一个装饰器装饰不同的函数的时候,可以把装饰器写在最上面,在函数的上面单独一行@装饰器名字

    import time
    def outter(func1):
        # func = index的内存地址
        def wrapper(*args,**kwargs):
            start = time.time()
            res = func1(*args,**kwargs)  # index的内存地址
            stop = time.time()
            print(stop - start)
            return res
        return wrapper
    
    @outter
    def index(x,y,z):
        time.sleep(3)
        print('index%s %s %s' %(x,y,z))
        return 666

    装饰器模板

    def outter(func):
        def wrapper(*args,**kwargs):
            # 1.调用原函数
            # 2.增加新功能
            res = func(*args,**kwargs)
            return res
        return wrapper

     加了装饰器之后如果需要保持和原函数的属性一直,操作如下:应用wraps

    import time
    from functools import wraps  # 导入wraps功能
    
    def timmer(func):
        '''计时器'''
        @wraps(func)  # 自动将原函数func的属性赋值给wrapper
        def wrapper(*args,**kwargs):
            strat = time.time()
            res = func(*args,**kwargs)
            stop = time.time()
            print(stop - strat)
            return res
        # 手动将原函数的属性赋值给wrapper
        # 1.函数wrapper.__name__ = 原函数.__name__
        # 2.函数wrapper.__doc__ = 原函数.__doc__
        # 1.wrapper.__name__ = func.__name__
        # 2.wrapper.__doc__ = func.__doc__
        return wrapper
    
    @timmer
    def login_in(x):
        '''登入验证'''
        time.sleep(2)
        print('登入成功!',x)
    login_in(222)
    print(login_in.__name__)
    print(login_in.__doc__)
    
    # >>>登入成功! 222
    #>>>2.0001063346862793
    # >>>login_in
    # >>>登入验证

    有参装饰器

      应用原因

    # 由于语法糖的限制,outter函数只能有一个参数,并且函数知识用来接收被修饰对象的内存地址
    def outter(func):  # outter 的参数也不能改动
        def wrapper(*args,**kwargs):  # wrapper的参数不能改动
            res = func(*args,**kwargs)
            return res
        return wrapper

    如果outter需要接受多个参数时,在无参装饰器的基础上再套一层,为被装饰对象多传值

    def auth(a,b,c):
        def outter(func):  # outter 的参数也不能改动
            def wrapper(*args,**kwargs):  # wrapper的参数不能改动
                res = func(*args,**kwargs)
                return res
            return wrapper
        return outter
    
    @auth(a = 111, b = 222, c = 333)
    def logn_in(x):
        pass

    多个装饰器:

    加载顺序是自下而上的;执行顺序是自上而下的。

    五.迭代器

      是指迭代(是一个重复的过程)取值的工具,基于上一次结果而继续的,单纯的重复不是迭代。

      可迭代对象:但凡内置方法中有__iter__方法的都称为可迭代对象

      迭代器对象:有__iter__()同时有__next__()方法

    迭代器适用所有类型:(字符串、列表、字典、元组、集合、文件)

    a = 'afsafacasd'
    a_iterator = a.__iter__()  # 迭代器
    while True:
        try:
            print(a_iterator.__next__())
        except StopIteration:
            break

    以下代码与上面的功能一样:

    1.调出a.__iter__(),得到一个迭代器

    2.调出迭代器下面的__next__()方法,拿到一个返回值赋值给k。

    3.循环步骤2,直到异常出现,跳出循环。

    a = 'afsafacasd'
    for k in a:
        print(k)

    总结:

      优点:①为序列和非序列类型提供了一种统一的取值方法;②惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。

      缺点:①除非取尽,否则无法获取迭代器的长度;②一次只能取一个值,如果取完了,需要重新调用迭代器才能够继续取值。

    六、生成器

      本质就是迭代器;是自定义的迭代器

    def func():
        print('第一次')
        yield 1         # yield 函数在运行时,遇到yield会停下来,
                #将yield后面的值当做本次的调用结果返回
    print('第二次') yield 2 print('第三次') yield 3 print('第四次') yield 4 g=func() res = next(g) print(res)

    yield作为表达式的用法:

    def dog(y):
        print('狗狗%s准备吃东西了'%y)
        while True:
            x = yield  # yield 接收到的是send的过来的值,
                # 但是一开始的时候必须send(None)
    print('狗狗%s吃了%s'%(y,x)) g = dog('小黑') g.send(None) g.send('包子') g.send('饼干') g.send('骨头')

    七、三元表达式

    语法格式: 条件成立返回的值 if 条件 else  条件不成立返回的值

    列表生成式:l = [表达式 for i in 可迭代对象 if 条件]

  • 相关阅读:
    PHP-redis命令之 列表(lists)
    PHP-redis命令之 散列(hashes)
    PHP-redis命令之 字符串 (strings)
    CentOS 7.0:搭建SVN服务器
    Redis 数据类型分析 字符串 哈希 列表 集合 有序集合 优缺点 分析 注意事项 存储结构
    CentOS 7安装配置Redis数据库
    封装微信分享到朋友/朋友圈js
    PHP 微信分享(及二次分享)
    Ajax登陆,使用Spring Security缓存跳转到登陆前的链接
    IDEA thymeleaf ${xxx.xxx}表达式报错,红色波浪线
  • 原文地址:https://www.cnblogs.com/Holmes-98/p/14289989.html
Copyright © 2011-2022 走看看