函数嵌套,闭包,装饰器

名称空间

命名空间:存放名字和值的关系的空间

命名空间分类:

  内置命名空间  >>>存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间

  全局命名空间  >>> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间       

  局部命名空间  >>>在函数中声明的变量会放在局部命名空间

加载顺序:

  内置命名空间 >>> 全局命名空间 >>> 局部命名空间

取值顺序:

       局部命名空间 >>> 全局命名空间 >>> 内置命名空间

作用域命名空间:         

  全局作用域:全局命名空间 + 内置命名空间       

  局部作用域:局部命名空间   

内容查看:

globals()  >>>查看全局作用域中的内容

locals()    >>>查看局部作用域中的变量和函数信息

 

函数嵌套

函数嵌套只要遇见了函数名+()就是在调用函数

函数顺序:

1

def func_1():    # 1定义func_1
    print("1")   #                         6打印“1”
                 #
def func_2():    # 2定义func_2
    print ("2")  #             4打印“2”
    func_1()     #             5调用func_1  7返回调用者
    print("3")   #                          8打印“3”
func_2()         # 3调用func_2               9返回func_2调用
print("4")       #                          10打印“4”

#2
#1
#3
#4

2

def func_1():      #1定义函数func_1
    print("1")              #4打印“1”
    def func_2():           #5定义func_2  
        print("2")                        #8打印“2”
    print("3")              #6打印“3”
    func_2()                #7调用函数func_2  #9返回func_2调用者
    print("4")                         #10打印“4”
print("5")         #2打印“5”
func_1()           #3调用func_1            #11返回func_1调用者
print("6")                              #12打印“6”

#5
#1
#3
#2
#4
#6

 

global、nonlocal

global在函数内部修改全局变量,没有的新声明一个。

a = 100   《global:将变量修改为全局变量》
def func():
    global a
    a = 25
    print(f"函数:{a}")    #函数:25
func()
print(f"内层:{a}")        #内层:25

nonlocal 修改上一级变量,没有的继续向上查找,到最外层结束,没有时会报错,不能修改全局的。

a = 100  《nonlocal:修改就近一层变量》
def func1():
    a = 25
    def func2():
        nonlocal a
        a = 10
        print(f"内层:{a}")    # 内层:10
    func2()
    print(f"函数:{a}")    #函数:10
func1()
print(f"内层:{a}")    #内层:100

 

 

函数名

函数名是一个变量与括号配合可以执行函数

函数名函数的内存地址

def func():
    print('1')
print(func)        #<function func at 0x0000000002071EA0>

 

 函数名可以赋值给其他变量

def func():
    print('1')
a = func
a()         #1     打印了“1”,说明函数被调用

 

 函数名可以作为容器类数据类型的元素

def func1():
    print("AA")
def func2():
    print("BB")
def func3():   
    print("CC")
lst = [func1, func2, func3]
for i in lst:
     i()
#AA
#BB
#CC

 

 函数名可以当做函数的参数

def func():
    print("a")
def func1(x):
    print("b")
    x()
func1(func)

# b
# a

 

 函数名可以作为函数的返回值

def func1():    1
    print("a1")   3
    def func2():   4
        print("b")          9
    print("a2")       5
    return func2       6
fn = func1()    2    7
fn()            8     10
# a1
# a2
# b

 

 闭包

闭包:内层函数引用外层函数变量()非全局变量)的嵌套函数

def func1()  《闭包》
    a = "abc"
    def func2():
        print(a)
    func2()
func1()
# 结果: abc

 

 闭包检测

def func1(): 《检测闭包__closure__,是:cell...,否:None》
    a = "abc"
    def func2():
        print(a)
    func2()
    print(f"func2闭包判断:{func2.__closure__}")
func1()
print(f"func1闭包判断:{func1.__closure__}")

# abc
# func2闭包判断:(<cell at 0x0000000001DF6558: str object at 0x0000000001DAB340>,)
# func1闭包判断:None

 

 闭包调用

def outer():   《执行完外部函数返回内部函数名,然后加括号就可调用》
    name = "alex"   
    # 内部函数   
    def inner():       
        print(name)   
    return inner
fn = outer()   # 访问外部函数, 获取到内部函数的函数地址
fn()    # 访问内部函数  

 

 嵌套多层时

def func1():   《嵌套多层时一层一层往回返》
    def func2():       
        def func3():       
            print("嘿嘿")      
        return func3 
    return func2
func1()()()    

 

 闭包的优点

保护变量不被外界修改

使变量生命周期延长

节省开辟空间和销毁空间的时间差

装饰器

 

装饰内容的一个工具

开放封闭原则

  对扩展开放

  对修改源代码封闭

  不改变调用方式

 作用

  不改变源代码的基础上添加功能

def inner(x):    《装饰器,装饰函数inner(),被装饰函数func()》
    def wapeer():
        start_time = time.time()  #时间戳,记录执行时的时间点
        x()
        end_time = time.time()  #时间戳,记录执行时的时间点
        print(end_time - start_time)
    return wapeer
import time
def func():
    time.sleep(2)   #暂停2秒
    print("睡2秒")
func = inner(func)
func()
# 睡2秒
# 2.0001144409179688

 

语法糖

被装饰的函数名 = 装饰器的名称(被装饰的函数名)

def inner(x):    《装饰器,装饰函数inner(),被装饰函数func()》
    def wapeer():
        start_time = time.time()  #时间戳,记录执行时的时间点
        x()
        end_time = time.time()  #时间戳,记录执行时的时间点
        print(end_time - start_time)
    return wapeer
import time

@inner #语法糖
def func(): time.sleep(
2)   #暂停2秒 print("睡2秒")               #省去了'func = inner(func)'是语法糖的原始机制 func() # 睡2秒 # 2.0001144409179688

 简单的装饰器

#简单的装饰器模式
def adorner(func):
    def inner(*args,**kwargs):
        """被装饰函数调用前"""
        ret = func()
        """被装饰函数调用后"""
        return ret
    return inner
@adorner
def foo(x,y):
    print(x,y)
foo(1,1)

 

functools import wraps

装饰多个函数时,保证被装饰函数的name的值保持不变

 

 

from  functools import wraps
def adorner(func):
    @wraps(func) #加在最内层函数上方,可以查看函数名、注释等
    def inner(*args,**kwargs):
        """被装饰函数调用前"""
        ret = func(*args,**kwargs)
        """被装饰函数调用后"""
        return ret
    return inner
@adorner
def foo(x,y):
    """
    打印参数值
    :param x:
    :param y:
    :return:
    """
    print(x,y)
foo(1,1)
print(f"函数注释{foo.__doc__}")
print(f"函数名{foo.__name__}")
可以查看函数注释的装饰器模式

 

带参数的装饰器

def outer(flag):
    def adorner(func):
        def inner(*args,**kwargs):
            if flag:
                print('''执行函数之前要做的''')
            re = func(*args,**kwargs)
            if flag:
                print('''执行函数之后要做的''')
            return re
        return inner
    return adorner

@outer(True)  # True时可以执行修饰动作,False时不执行修饰动作
def func():
    print(111)

func()
带参数的装饰器

 

多个装饰器修饰一个函数

def adorner_1(func):
    def inner(*args,**kwargs):
        print("adorner_1,函数前的")
        func(*args,**kwargs)
        print("adorner_1,函数后的")
    return inner

def adorner_2(func):
    def inner(*args,**kwargs):
        print("adorner_2,函数前的")
        func(*args,**kwargs)
        print("adorner_2,函数后的")
    return inner

@adorner_2
@adorner_1
def f():
    print("调用函数f")

f()

# adorner_2,函数前的
# adorner_1,函数前的
# 调用函数f
# adorner_1,函数后的
# adorner_2,函数后的
View Code

 

 

总结:

装饰器本质是闭包
语法糖单独一行
遵守开放封闭原则,开发对外扩展,封闭修改源代码。
不能修改调用方式

装饰器的应用:
不能说测试函数运行时间
为函数增加一些功能
校验用户登录的时候,Diango,面向对象

 

 

函数嵌套和闭包

 

posted on 2019-01-15 22:16  六月_海动  阅读(81)  评论(0)    收藏  举报