• python3 闭包函数 装饰器


    闭包函数

    1.闭:定义在函数内部的函数 2.包:内部函数引用了外部函数作用域的名字

    在函数编程中经常用到闭包。闭包是什么,它是怎么产生的及用来解决什么问题呢。给出字面的定义先:
    闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数+引用环境)(想想Erlang的外层函数传入一个参数a, 内层函数依旧传入一个参数b, 内层函数使用a和b, 最后返回内层函数)
    这个从字面上很难理解,特别对于一直使用命令式语言进行编程的程序员们。本文将结合实例代码进行解释。
    函数是什么都知道:函数只是一段可执行代码,编译后就“固化”了,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数了。
    在函数式编程语言中,函 数是一等公民(First class value:第一类对象,我们不需要像命令式语言中那样借助函数指针,委托操作函数),函数可以作为另一个函数的参数或返回值,可以赋给一个变量。
    函数可 以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。如:# def outter():
    # x = 111
    # def inner():
    # print(x)
    # return inner
    # res = outter() # res就是inner函数内存地址


    # def func():
    # x = 333
    # res()
    # func()

    python中的闭包从表现形式上定义(解释)为:
    如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
    这个定义是相对直白的,好理解的,不像其他定义那样学究味道十足(那些学究味道重的解释,在对一个名词的解释过程中又充满了一堆让人抓狂的其他陌生名词,不适合初学者)。下面举一个简单的例子来说明。

    # 给函数体传值的第一种方式 传参
    # def index1(username):
    # print(username)
    #
    # # 给函数体传参的第二种方式 闭包
    # def outter(x,y):
    # # x = 1
    # # y = 40
    # def my_max():
    # if x > y:
    # return x
    # return y
    # return my_max
    # res1 = outter(1,40) # res就是my_max函数的内存地址
    # print(res1())
    # print(res1())
    # print(res1())
    # res2 = outter(90,200)
    # print(res2())
    # print(res2())
    # print(res2())





    import requests


    # 第一个直接给函数传参
    url1 = 'https://www.baidu.com'
    url2 = '...'
    def my_get(url):
    response = requests.get(url)
    if response.status_code == 200:
    print(len(response.text))

    my_get(url1)
    my_get(url1)
    my_get(url1)
    my_get('https://www.baidu.com')
    my_get('https://www.baidu.com')
    my_get('https://www.baidu.com')





    # 第二种给函数传参的方式 闭包
    def outter(url):
    # url = 'https://www.jd.com'
    def my_get():
    response = requests.get(url)
    if response.status_code == 200:
    print(len(response.text))
    return my_get
    my_jd = outter('https://www.jd.com')
    my_jd()
    my_jd()
    my_baidu = outter('https://www.baidu.com')
    my_baidu()
    my_baidu()
    my_baidu()
    二,使用闭包注意事项

    1,闭包中是不能修改外部作用域的局部变量的
    除非事先声明globl nonlocal 变量类型
    三,作用
    说了这么多,不免有人要问,那这个闭包在实际的开发中有什么用呢?闭包主要是在函数式开发过程中使用。以下介绍两种闭包主要的用途。
     
    用途1,当闭包执行完后,仍然能够保持住当前的运行环境。
    用途2,闭包可以根据外部作用域的局部变量来得到不同的结果,这有点像一种类似配置功能的作用,我们可以修改外部的变量,闭包根据这个变量展现出不同的功能。比如有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行。
     
     
     

    装饰器:

    器:就是一个工具
    装饰:给被装饰对象添加新的功能

    为什么要用装饰器
    开放封闭原则:
    开放:对扩展开放
    封闭:对修改封闭

    装饰器(可调用对象)必须遵循的两个原则:
    1.不改变被装饰对象源代码
    2.不改变被装饰对象(可调用对象)调用方式
    def index():
    pass
    index()

    如何用

    from functools import wraps
     
    def requires_auth(f):
        @wraps(f)
        def decorated(*args, **kwargs):
            auth = request.authorization
            if not auth or not check_auth(auth.username, auth.password):
                authenticate()
            return f(*args, **kwargs)
        return decorated



    这里我们写一个日志的装饰器
    from
    functools import wraps def logit(func): @wraps(func) def with_logging(*args, **kwargs): print(func.__name__ + " was called") return func(*args, **kwargs) return with_logging @logit def addition_func(x): """Do some math.""" return x + x result = addition_func(4) # Output: addition_func was called

    更进一步 我们可以 继续封装装饰器 如下

    from functools import wraps
     
    def logit(logfile='out.log'):
        def logging_decorator(func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                # 打开logfile,并写入内容
                with open(logfile, 'a') as opened_file:
                    # 现在将日志打到指定的logfile
                    opened_file.write(log_string + '
    ')
                return func(*args, **kwargs)
            return wrapped_function
        return logging_decorator
     
    @logit()
    def myfunc1():
        pass
     
    myfunc1()
    # Output: myfunc1 was called
    # 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
     
    @logit(logfile='func2.log')
    def myfunc2():
        pass
     
    myfunc2()
    # Output: myfunc2 was called
    # 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串
    装饰器类
    现在我们有了能用于正式环境的logit装饰器,但当我们的应用的某些部分还比较脆弱时,异常也许是需要更紧急关注的事情。
    比方说有时你只想打日志到一个文件。而有时你想把引起你注意的问题发送到一个email,同时也保留日志,留个记录。这是一个使用继承的场景,但目前为止我们只看到过用来构建装饰器的函数。 幸运的是,类也可以用来构建装饰器。那我们现在以一个类而不是一个函数的方式,来重新构建logit。
    from functools import wraps class logit(object): def __init__(self, logfile='out.log'): self.logfile = logfile def __call__(self, func): @wraps(func) def wrapped_function(*args, **kwargs): log_string = func.__name__ + " was called" print(log_string) # 打开logfile并写入 with open(self.logfile, 'a') as opened_file: # 现在将日志打到指定的文件 opened_file.write(log_string + ' ') # 现在,发送一个通知 self.notify() return func(*args, **kwargs) return wrapped_function def notify(self): # logit只打日志,不做别的 pass

    装饰器的执行顺序检测

    from functools import wraps
    def outter(func):
        @wraps(func)  # 装饰器修复技术
        def inner(*args,**kwargs):
            """
            我是inner函数
            :param args:
            :param kwargs:
            :return:
            """
            print('执行被装饰函数之前 你可以执行的操作')
            res = func(*args,**kwargs)
            print('执行被装饰函数之后 你可以执行的操作')
            return res
        return inner
    
    @outter  # index = outter(最原始的index内存地址)
    def index():
        """
        这是index函数
        :return:
        """
        pass


    print(index)
    print(help(index)) # 查看函数的注释
    print(index.__name__) # 查看函数名字符串形式
    index()
    """
    用户查看被装饰函数的函数名的时候查看到的就是被装饰函数本身
    用户查看被装饰函数的注释的时候查看到的就是被装饰函数的注释
    """

    def outter1(func1):
        print('加载了outter1')
        def Decorators1(*args,**kwargs):
            print('执行了Decorators1')
            res1=func1(*args,**kwargs)
            print('执行了func1')
            return res1
        return Decorators1
    def outter2(func2):
        print('加载了outter2')
        def Decorators2(*args,**kwargs):
            print('执行了Decorators2')
            res2=func2(*args,**kwargs)
            print('执行了func2')
            return res2
        return Decorators2
    def outter3(func3):
        print('加载了outter3')
        def Decorators3(*args,**kwargs):
            print('执行了Decorators3')
            res3=func3(*args,**kwargs)
            print('执行了func3')
            return res3
        return Decorators3
    @outter1  # index = outter1(wapper2)
    @outter2  # Decorators2 = outter2(Decorators3)
    @outter3  # Decorators3 = outter3(最原始的index函数内存地址)
    def index():
        print('from index')
    
    """
    加载了outter3
    加载了outter2
    加载了outter1
    
    执行了Decorators1
    执行了Decorators2
    执行了Decorators3
    from index
    """
    index()

    执行结果为:


    加载了outter3
    加载了outter2
    加载了outter1
    执行了Decorators1
    执行了Decorators2
    执行了Decorators3
    from index
    执行了func3
    执行了func2
    执行了func1

    Process finished with e

  • 相关阅读:
    win10 mysql5.7忘记密码如何解决
    win10 mysql5.7指定某个配置文件启动
    kubernetes配置(kubeconfig)对多集群的访问
    kubernetes中kubeconfig的用法
    rancher v2.2.4创建kubernetes集群出现[etcd] Failed to bring up Etcd Plane: [etcd] Etcd Cluster is not healthy
    kubernetes 强制删除istio-system空间,强制删除pod
    rancher2.0 自定义应用商店(catalog)
    docker-compose安装及docker-compose.yml详解
    细述kubernetes开发流程
    轻松了解DNS劫持
  • 原文地址:https://www.cnblogs.com/Sunbreaker/p/11171282.html
Copyright © 2020-2023  润新知