zoukankan      html  css  js  c++  java
  • 9.装饰器

    装饰器

    闭包函数

    思考练习

    def addx(x):
        def adder(y):return x+y
        return adder
    c = addx(8)
    print(c(10))

    要计算这段代码的结果,首先需要具备“python中一切皆对象”的思想。在python中,函数也是一样可以被赋值传参加入运算的。这就成为闭包函数实现前提,因为闭包的梗概(我理解)就在于:定义一个函数,并且返回值为子函数方法。
    上述代码中addx(x)是一个需要传参x进入的函数,并且有一个子函数adder(y)同样需要被传参y。addx的返回值就是adder方法
    我们都知道函数名称后面跟‘()’就是运行函数,函数通常会运算并且得出一个值,当你暂时不需要这个值的时候,你可以先return func,而不添加(),这样做的意义就在于,保留返回了这个函数运算的方法,在需要传参进入时候再进行传参。

    当然也可以直接输出这个func,这样的结果就是这个函数在内存的存储位置。

    上述代码中,c = addx(8)完成了addx中对x的传参,传入x之后adder(y)返回的语句就相当于8+y,并且adder返回给addx的方法,仍然是adder(y)

    所以分解输出式子:
    c(10)==addx(8)(10)==【adder(10)且已知x = 8】==8+10==18

    为什么要使用装饰器

    python中装饰器的多种用途:
    输出日志、参数检查、代理设置、计数计时、结果缓存等。

    装饰器可以在不影响原代码的前提下,为原代码输出结果附加一些内容

    开放封闭原则:软件实体应该对扩展开放,而对修改封闭。开放封闭原则是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化,降低耦合,而开放封闭原则正是对这一目标的最直接体现。
    开放封闭原则主要体现在两个方面:
    对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
    对修改封闭,意味着类一旦设计完成,就可以独立其工作,而不要对类尽任何修改。

    装饰器范例代码:

    (一)老师教的定义方式

    import time     #载入time函数库
    
    def timer(func):        #定义装饰器名称
        def wrapper():      #定义用于返回闭包的内建函数
            start_time = time.time()
            func()
            end_time = time.time()
            print('func run time is %s'%(end_time-start_time))
        return wrapper      #返回闭包函数的方法,后面添加括号的话,就执行这个方法并且获得结果
    
    @timer          #语法糖,注意这个@语法要在‘def’前面使用
    def index():
        time.sleep(1)
        print('this is a test func')
    
    index()

    (二)网上的花活

    https://zhuanlan.zhihu.com/p/23510985

    # 构建装饰器
    def logging(func):
        @functools.wraps(func)
        def decorator():
            print("%s called" % func.__name__)
            result = func()
            print("%s end" % func.__name__)
            return result
        return decorator
    
    # 使用装饰器
    @logging
    def test01():
        return 1
    
    # 测试用例
    print(test01())
    print(test01.__name__)

    上面这个functools在IDE中有报错,可能是一个外部调用方法,所以这种方法暂时不管,下次看到的时候,只要知道这是在定义一个装饰器就可以了。

    考虑到装饰器需要适配多种参数的函数,提高复用率。
    所以需要这样定义装饰器:

    import time
    def timer(func):
        def wrapper(*args,**kwargs):
            start_time = time.time()
            func(*args,**kwargs)
            end_time = time.time()
            print('======')
        return wrapper

    结合闭包的概念,梳理一下装饰器运行的逻辑:

    定义一个装饰器名称函数
    定义一个装饰器wrapper,可以提供多种参数的传参
    装饰器功能,
    装饰目标函数,和wrapper相同的传参条件
    装饰器效果(可有可无)
    返回wrapper不加括号

    我所理解的不加括号的意义,就是暂时不调用这个闭包内的函数,直到在外部调用时,手动添加上'()',就执行这个函数的功能。这个方法刚好和return func()相反,因为添加括号后,返回的就是一个结果值。而不添加,就是一种运算。

    有参装饰器

    def auth():
        def wrapper(*args,**kwargs):
            name = input('username:')
            password = input('password:')
            if name =='scott' and password =='123':
                print('auth successful')
                res = func(*args,**kwargs)
                return res
            else:
                print('auth error')
        return wrapper
    
    
    @auth      #index = auth(index)
    def index():
        print('welcome to index page')
    

    思考:

    有一个运行时间计数函数装饰器
    有一个用户登录认证装饰器
    能否实现“当运行时间计数超过一定时间后,提示用户登录认证失败”
    理清装饰器运行的包裹层关系:

    @time
    @auth_check
    def func()
    
    func() = time(auth_check(func))

    但是如果需要校验函数的运行时间是否超时,就应该把time放在里面

    @auth_check
    @time
    def func()

    虽然这样看起来递进关系对了,但是装饰器能否向被定义的函数进行传参,或者装饰器之间能否进行传参?
    老师回答:装饰器并不能向装饰的函数进行传参或者运算
    如果需要一个对函数运行时间进行判断并且输出结果的装饰器:

    import time
    def timer(func):
        def wrapper():
            start_time = time.time()
            func()
            end_time = time.time()
            res = end_time-start_time
            if res<= 60:
                print('函数在时限内运行完成')
            else:
                print('函数运行超时')
            print('func run %s'%(end_time-start_time))
        return wrapper
    
    @timer

    <wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

  • 相关阅读:
    Elasticsearch Query DSL 整理总结(三)—— Match Phrase Query 和 Match Phrase Prefix Query
    Elasticsearch Query DSL 整理总结(二)—— 要搞懂 Match Query,看这篇就够了
    Elasticsearch Query DSL 整理总结(一)—— Query DSL 概要,MatchAllQuery,全文查询简述
    Elasticsearch Java Rest Client API 整理总结 (三)——Building Queries
    Elasticsearch date 类型详解
    python 历险记(五)— python 中的模块
    python 历险记(四)— python 中常用的 json 操作
    python 历险记(三)— python 的常用文件操作
    Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI
    Elasticsearch Java Rest Client API 整理总结 (一)——Document API
  • 原文地址:https://www.cnblogs.com/scott-lv/p/7468939.html
Copyright © 2011-2022 走看看