首页 > 代码库 > Python开发基础-Day7-闭包函数和装饰器基础

Python开发基础-Day7-闭包函数和装饰器基础

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

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)

 

Python开发基础-Day7-闭包函数和装饰器基础