zoukankan      html  css  js  c++  java
  • python基础之闭包函数和装饰器

    补充:全局变量声明及局部变量引用

    python引用变量的顺序: 当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量

    global关键字用来在函数或其他局部作用域中使用全局变量,声明后可以在其他作用于中修改和使用

    x=1      #全局赋值变量
    def foo():
        global x    #函数内部全局声明变量x
        x=1111111    #函数内部修改全局变量x
        print(x)
    foo()
    print(x)

    global声明的变量在任何作用域都能够修改,所以一般非必要情况下要避免这种声明操作。

    nonlocal关键字用来在函数或其他作用域中使用外层(非全局)变量,一般用在函数嵌套。

    def f1():
        # x=2
        def f2():
            x=3
            def f3():
                nonlocal x
                x=1111
                # print('f3',x)
            f3()
            print('f2',x)
        f2()
        # print('f1',x)
    f1()

    如上,如果在f3的函数体内部不做nonlocal声明x,即将nonlocal x注释掉,那么函数体f2内的print将打印的结果是“f2 3”,声明后的结果为“f2 1111”。

    闭包函数

    闭包函数定义:

    函数内部定义的函数称为内部函数,该内部函数包含对外部(上层)作用域,而不是对全局作用域名字的,那么该内部函数称为闭包函数

    定义闭包函数:

    定义闭包函数的基本形式
    def 外部函数名():
        内部函数需要的变量
        def 内部函数():  #基本函数
            引用外部的变量
        return 内部函数 #不加括号,返回内存地址

    闭包函数指的是内部函数

    闭包函数包含对外部作用域的引用,而非全局作用域的引用

    闭包函数的特点:自带向外的作用域,延迟计算(惰性计算,用到的时候计算)

    示例:

    name='alex'    #全局定义的变量
    def func():    
        name='egon'  #函数func调用的变量,外部作用域
        def bar():    #内部函数
            print(name)  #内部函数bar打印name的作用域除了bar函数自己本身,还有func函数内部
        return bar    #调用func函数时的返回值为bar函数本身,而非bar函数执行结果,返回的是bar函数的一段内存地址
    b=func()      #b接收func函数的返回值,即bar函数的内存空间,现在的b就等于是bar
    print(b)
    b()        #执行b即执行bar函数的print(name)打印操作,而非全局定义的name
    #print(b.__closure__[0].cell_contents)  #返回作用域空间的第一个变量值
    #print(b.__closure__)      #作用域空间信息
    
    输出结果
    <function func.<locals>.bar at 0x0000021CA66CB8C8>
    egon

    自带向外的作用域,即bar函数包含func函数的作用域,也包含bar本身的作用域,即bar能够调用name='egon'

    作用域在函数定义的时候已经固定了,也就是说,无论在什么地方调用b(),b函数的作用域永远用的是bar函数定义时候的作用域。

    装饰器基础

    程序源代码的原则:对功能扩展开放,对修改源代码封闭

    即可以在源代码的基础上扩展功能,而不能修改源代码(原因是,系统上线了修改源代码,改错了咋整)

    装饰器就是用来进行源代码功能能扩展的一种实现方式。

    装饰器本质上是任意可调用的对象,目前能够理解的就是是函数,而被装饰的对象也可以是任意可调用的对象。

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

    装饰器原则:不修改源代码,不修改调用方式,还要能够增加新功能

    示例一:当调用函数index时候,随机等待0-4秒打印hello world

    #原功能
    import time
    import random
    def index():
        time.sleep(random.randrange(1,5))
        print('hello world')
    index()

    示例二:扩展功能统计index的执行时间,包括随机等待的时间

    import time
    import random
    
    def index_new(func):
        def timmer():
            start_time=time.time()
            func()
            stop_time=time.time()
            print('time:%s' %(stop_time-start_time))
        return timmer
    
    def index():    #源代码并不改变
        time.sleep(random.randrange(1,5))
        print('hello world')
    
    index=index_new(index)
    index()
    
    输出结果:
    hello world
    time:3.000032663345337

    示例三:装饰器调用语法

    def index_new(func):
        def timmer():
            start_time=time.time()
            func()
            stop_time=time.time()
            print('time:%s' %(stop_time-start_time))
        return timmer
    #使用@符号进行调用
    @index_new  #index=index_new(index)
    def index():
        time.sleep(random.randrange(1,5))
        print('hello world')
    
    index()

    示例四:定义多个装饰器,增加多个功能模块

    import time
    import random
    #装饰器1:计时模块
    def timmer(func):
        def wrapper():
            start_time = time.time()
            func()
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
        return wrapper
    #装饰器2:认证模块
    def auth(func):
        def deco():
            name=input('name: ')
            password=input('password: ')
            if name == 'egon' and password == '123':
                print('login successful')
                func() #wrapper()
            else:
                print('login err')
        return deco
    
    #被装饰函数
    @auth #index=auth(wrapper) #index=deco                      #index=auth(wrapper) #index=deco
    @timmer #index=timmer(index) #index=wrapper
    def index():
        # time.sleep(random.randrange(1,5))
        time.sleep(3)
        print('welecome to index page')
    
    #并没有调用任何装饰器
    def home():
        time.sleep(random.randrange(1,3))
        print('welecome to HOME page')
    
    index() #deco()
    home()

    当要调用多个装饰器的时候,调用的顺序是,谁先执行就先调用哪一个,顺序是从上而下,但是内部计算的顺序是从下而上的

    示例五:源代码需要传入参数的,以及需要返回值的

    import time
    import random
    #装饰器
    def timmer(func):
        def wrapper(*args,**kwargs):  #*args和**kwargs能够接收任意的参数,并且可以不存在,接收后原封不动传入到func调用的函数
            start_time = time.time()
            res=func(*args,**kwargs)    #返回值赋值,需要传入的函数有返回值才行
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res    #抛出返回值
        return wrapper
    #被装饰函数
    
    @timmer
    def index():
        time.sleep(random.randrange(1,5))
        print('welecome to index page')
    @timmer
    def home(name):
        time.sleep(random.randrange(1,3))
        print('welecome to %s HOME page' %name)
        return 123123123123123123123123123123123123123123
    
    res1=index()
    print('index return %s' %res1)
    res2=home('egon') #wraper()
    print('home return %s' %res2)
  • 相关阅读:
    Bootstrap(项目2)
    Bootstrap(项目1)
    Bootstrap(Carousel幻灯片)轮播图
    Bootstrap(滚动监听)
    Bootstrap基础10(标签页)
    Bootstrap基础9(工具提示框、警告框、弹出框)
    Bootstrap基础8(模态框(弹窗))
    Bootstrap基础7(标签、徽章、大屏展播、页面标题、缩略图、进度条、面板、折叠效果)
    Bootstrap基础6(路径导航)
    2018~2019学年下学期《计算机图像处理》
  • 原文地址:https://www.cnblogs.com/lidagen/p/7049241.html
Copyright © 2011-2022 走看看