zoukankan      html  css  js  c++  java
  • python——装饰器

    一、名称空间(name space)

      存放名字的地方,存什么名字呢?

    如变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方

    名称空间共3种:

    • locals: 是函数内的名称空间,包括局部变量和形参
    • globals: 全局变量,函数定义所在模块的名字空间
    • builtins: 内置模块的名字空间

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

    作用域即范围

    • 全局范围:全局存活,全局有效
    • 局部范围:临时存活,局部有效

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

    作用域查找顺序:

     locals -> enclosing function(相邻的) -> globals -> __builtins__LEGB

    二、闭包

    有一下代码:

    def outer():
        name = 'alex'
    
        def inner():
            print("在inner里打印外层函数的变量",name)
    
        return inner
    
    
    f = outer()
    f()
    
    输出:
    在inner里打印外层函数的变量 alex
    View Code

    外层函数outer返回了内层函数的函数名inner给变量f,在函数外部执行语句:f()是就相当于调用了内层函数inner,并且inner又引用了外层函数的变量name。

    对于这种,外层函数返回子函数的函数名(即子函数内存地址),在函数外调用了子函数,子函数又引用了外层函数的变量,就形成了闭包。

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

    三、装饰器

      可以理解为一种装饰函数的工具,其本质就是一个函数。

      软件开发的原则之一:开放—封闭原则

    开放:对现有功能的扩展开放

    封闭:已实现的功能代码块不应该被修改

      所以,装饰器的原则是:

    1、不能修改被装饰函数的源码

    2、不能修改被装饰函数的调用方式

      高阶函数+嵌套函数=装饰器

    高阶函数:1、将函数名作为实参传递给另一个函数(不改变源码)

         2、return返回另一个函数名(不改变函数的调用方式)

    装饰器实例

    你是一家视频网站的后端开发工程师,你们网站已上线运行了该模块

    def home():
        print("---首页----")
        
    
    def america():
        print("----欧美专区----")
    
    
    def japan():
        print("----日韩专区----")
    
    
    def henan():
        print("----河南专区----")
    
    
    home()
    america()
    japan()
    henan()
    View Code

    现在,你们老板跟你说,现在用户越来越多啦,准备将"america"和"henan"两个板块改为收费才能进入,所以你就要给它们新增一个登陆认证的功能,但是系统已经上线了,你是不可能修改源码的,用户一直也都习惯了这种调用方式去进去各板块,所以你想到了装饰器:

    status = False  # 用于判断用户登录状态
    
    
    def auth(func):  # 将函数作为参数传入  func=america or func = henan
        def inner():
            global status  # 定义全局变量
            _username = "qwe"  # 假设这是数据库用户信息
            _password = "123"
            if status is False:  # 未登录
                username = input("username:")
                password = input("password:")
                if username == _username and password == _password:  # 用户名与密码是否正确
                    print("33[35;1m-----Welcome-----33[0m")
                    status = True  # 修改用户登录状态
                else:
                    print("Wrong username or password")
            if status is True:  # 已登录
                print("33[35;1m-----用户已登录-----33[0m")
                func()  # 允许进入相关板块  america() or henan()
        return inner  # 返回内层函数名
    
    
    
    def home():
        print("---首页----")
    
    
    @auth  # 给函数加上装饰器,相当于执行:auth(america) ,稍后auth 会将函数inner返回,即america=inner
    def america():
        print("----欧美专区----")
    
    
    def japan():
        print("----日韩专区----")
    
    
    @auth  # 给函数加上装饰器
    def henan():
        print("----河南专区----")
    
    
    home()
    america()  # 此时的america已经被“偷梁换柱”,相当于inner()
    japan()
    henan()  # inner()
    
    输出:
    ---首页----
    username:qwe
    password:123
    -----Welcome-----
    -----用户已登录-----
    ----欧美专区----
    ----日韩专区----
    -----用户已登录-----
    ----河南专区----
    View Code

    你可以在里面传参数,最好使用非固定参数,因为万一有些函数你要传参,有些不用,方便动态管理:

    status = False  # 用于判断用户登录状态
    
    
    def auth(func):  # 将函数作为参数传入  func=america or func = henan
        def inner(*args, **kwargs):
            global status  # 定义全局变量
            _username = "qwe"  # 假设这是数据库用户信息
            _password = "123"
            if status is False:  # 未登录
                username = input("username:")
                password = input("password:")
                if username == _username and password == _password:  # 用户名与密码是否正确
                    print("33[35;1m-----Welcome-----33[0m")
                    status = True  # 修改用户登录状态
                else:
                    print("Wrong username or password")
            if status is True:  # 已登录
                print("33[35;1m-----用户已登录-----33[0m")
                func(*args, **kwargs)  # 允许进入相关板块  america() or henan()
        return inner  # 返回内层函数名
    
    
    
    def home():
        print("---首页----")
    
    
    @auth  # 给函数加上装饰器,相当于执行:auth(america) ,稍后auth 会将函数inner返回,即america=inner
    def america(n):  # 传递参数
        print(n)
        print("----欧美专区----")
    
    
    def japan():
        print("----日韩专区----")
    
    
    @auth  # 给函数加上装饰器
    def henan():
        print("----河南专区----")
    
    
    home()
    america("付费啦,可以看美剧啦!!!")  # 此时的america已经被“偷梁换柱”,相当于inner()
    japan()
    henan()  # inner()
    
    输出:
    ---首页----
    username:qwe
    password:123
    -----Welcome-----
    -----用户已登录-----
    付费啦,可以看美剧啦!!!
    ----欧美专区----
    ----日韩专区----
    -----用户已登录-----
    ----河南专区----
    View Code

    但是,老板又提新需求了,要求"america"板块用“QQ”认证,"henan"板块用“WeChat”认证,其实就是在装饰器外面再加一层函数:

    status = False  # 用于判断用户登录状态
    
    
    def outer(auth_login):
        def auth(func):  # 将函数作为参数传入
            def inner(*args, **kwargs):
                if auth_login == "QQ" or auth_login == "WeChat":
                    global status  # 定义全局变量
                    _username = "qwe"  # 假设这是数据库用户信息
                    _password = "123"
                    if status is False:  # 未登录
                        username = input("username:")
                        password = input("password:")
                        if username == _username and password == _password:  # 用户名与密码是否正确
                            print("33[35;1m-----Welcome-----33[0m")
                            status = True  # 修改用户登录状态
                        else:
                            print("Wrong username or password")
                    if status is True:  # 已登录
                        print("33[35;1m-----用户已登录-----33[0m")
                        func(*args, **kwargs)  # 允许进入相关板块  america() or henan()
                    else:
                        print("Wrong authentication login:", func)  # 认证方式错误提示
            return inner  # 返回内层函数名
        return auth
    
    
    
    def home():
        print("---首页----")
    
    
    @outer("QQ")  # 带参数的装饰器
    def america(n):  # 传递参数
        print(n)
        print("----欧美专区----")
    
    
    def japan():
        print("----日韩专区----")
    
    
    @outer("WeChat")  # 带参数的装饰器
    def henan():
        print("----河南专区----")
    
    
    home()
    america("付费啦,可以看美剧啦!!!")
    japan()
    henan()  # inner()
    View Code
  • 相关阅读:
    linq to sql 还没解决的问题
    js暂停函数,想做牛人的菜鸟遇到了问题。
    公司给我拿800/月 干不干啊?ASP.NET程序员
    android の Handler消息传递机制
    android の Activity & View | LayoutInflate
    ActionScript事件侦听addEventListener的参数详解
    java中String的intern方法和equals方法的使用
    java中short,int转换成byte数组及byte数组转换成short,int
    Flex组件中list里面的数据引用
    Flex中设置弹出窗口的弹出效果(alpha值的渐变和scale值的渐变)
  • 原文地址:https://www.cnblogs.com/yanlin-10/p/9016084.html
Copyright © 2011-2022 走看看