函数进阶:闭包装饰器

Posted neozheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数进阶:闭包装饰器相关的知识,希望对你有一定的参考价值。

命名空间(又称“名称空间”): 存放名字的地方  (概念性的东西)

例如:变量x = 1, 1存放在内存中,命名空间就是存放名字x与1绑定关系的地方。

名称空间有3种:

  • locals:是函数内的(或者是locals所在的那一层的)名称空间|,包括局部变量和形参
  • globals:全局变量
  • builtins: 内置模块的名字空间

 不同变量的作用域不同就是由这个变量所在的命名空间决定的

 作用域即范围:

1. 全局范围: 全局存活,全局有效

2. 局部范围: 临时存活, 局部有效

 

查看作用域方法: globals(),locals()

 

作用域的查找顺序: LEGB

L: locals

E: enclosing (相邻的)

G:globals

B: builtins 

 

闭包:

def func():
    n = 10
    def func2():
        print(func2:, n)
    return func2   #  没有执行func2, 只是把func2的函数名(func2的内存地址)

f = func()   #执行func函数, 此时func()得到的结果是func2的内存地址,即f就是func2的内存地址

f()    # 执行f, 由于f就是func2的内存地址,此时执行的就是func2函数

# 输出结果: 
# func2: 10    

#  在函数(func)外部执行了函数内部的子函数(func2),而且子函数(func2)还能够调用其父级函数(func)作用域里面所有的值。 这种现象就是闭包

 

装饰器:

软件开发“开放-封闭” 原则:已经实现的功能代码不允许被修改,但可以被扩展。

另外,不要改变别人函数的调用方式

 

现在公司有一个网站模块功能如下:

def home():
    print(---------主页----------)

def america():
    print(--------欧美专区-------)

def japan():
    print(--------日韩专区-------)

 

 

现在需要在america 和 japan这两个板块前加上以下登录认证功能:

login_status = False
def login():
    info = [neo, abc123]  # 储存的用户信息
    global login_status
    if not login_status:
        name_input = input(用户名:)
        password_input = input(密码:)

        if name_input == info[0] and password_input == info[1]:
            print(登陆成功)
            login_status = True
        else:
            print(密码错误)
            exit()
        else:
             print(用户已登录,通过检测)                
            
          

 

 

现有如下几种方法可选: 

1. 直接在America和Japan模块里面加上login认证程序, 如:

def japan():
    login()   # 把自己写的认证程序加到别人写好的模块里面
    print(--------日韩专区-------)

 

这种方式违反“封闭”原则,pass。

2. 把america和japan这两个函数名当做参数传到login函数里面,如:

login_status = False
def login(func):
    info = [neo, abc123]  # 储存的用户信息
    global login_status
    if login_status == False:
        name_input = input(用户名:)
        password_input = input(密码:)

        if name_input == info[0] and password_input == info[1]:
            print(登陆成功)
            login_status = True
        else:
            print(密码错误)
            exit()
    if login_status == True:
         print(用户已登录,通过检测)      
         func()   #把需要认证的模块函数名传进来调用执行

def home():
    print(---------主页----------)

def america(x,y,z):
    print(--------欧美专区-------,x,y,z)

def japan():
    print(--------日韩专区-------)

login(japan)   #需要认证时,就把函数名当做参数变量传给login函数

 

这种方式改变了原模块(如japan())的调用方式

 

3. 装饰器:

login_status = False
def login(func):
    def inner():
        info = [neo, abc123]  # 储存的用户信息
        global login_status
        if login_status == False:
            name_input = input(用户名:)
            password_input = input(密码:)

            if name_input == info[0] and password_input == info[1]:
                print(登陆成功)
                login_status = True
            else:
                print(密码错误)
                exit()
        if login_status == True:
             print(用户已登录,通过检测)      
         func()   #把需要认证的模块函数名传进来调用执行
    return inner  #login()执行的时候,得到的结果只是 把inner的函数名(内存地址)返回给login(func)

def home():
    print(---------主页----------)

def america():
    print(--------欧美专区-------)

def japan():
    print(--------日韩专区-------)

japan = login(japan)   # login(japan)的执行结果是得到了inner函数的内存地址,再赋值给前面的japan 变量后,变量japan就是inner函数的内存地址。
 japan()   # 此时执行japan函数其实执行的里面的inner函数,由于闭包的父级函数执行完后里面的变量内存并不会释放、子函数inner里面能够使用login函数里面的所有参数变量,所以inner里面的变量func执行的时候会向login函数调用其传入的先前的japan函数。 这就是装饰器的原理。



#装饰器的正规写法:
@login
def japan():
    print(---------日韩专区--------)

# 1.两个函数组成一个闭包,装饰函数做父级,被装饰的函数放在子级函数里面,子级函数名return给父级
# 2. 被修饰的函数名作为参数传给父级函数
# 3.子级函数里面包括装饰代码(如:登录认证)和 被装饰的函数(如:japan())

 

以上是关于函数进阶:闭包装饰器的主要内容,如果未能解决你的问题,请参考以下文章

python 基础篇 11 函数进阶----装饰器

Python函数进阶:闭包装饰器生成器协程

函数进阶——闭包,装饰器,生成器,迭代器

Python 进阶

Python 之 进阶学习

函数进阶:闭包装饰器