• Python 详解修饰器 附带 js使用修饰器


    修饰器

    功能

    修饰器的主要功能是,在不改变已有代码的情况下,为某一个类,方法等扩展功能

    首先看这样一段代码

    def foo():
        for i in range(10):
            print(i)
    foo()
    
    添加需求 打印日志

    现在需要在不改变这段代码前提下,计算出这段代码的运行时间日志

    import time
    
    
    def log(fun):
        print('开始时间:{}'.format(time.time()))
        fun()
        print('结束时间:{}'.format(time.time()))
    
    
    def foo():
        for i in range(10):
            print(i)
    
    
    log(foo)
    
    
    优化调用方式 处理多次调用

    我们将foo函数当成一个参数传递给了log(),在def log(fun)函数中,fun()就等同于foo(),好,现在可以显示运行的时间日志了,但是这样就改变了调用方式 需要使用log(foo)来调用,假设代码中使用了100次foo()现在需要打印每个foo()的运行日志,全部这样改是不现实的,我们需要优化一下

    import time
    
    
    def log(fun):
        def run_log():
            print('开始时间:{}'.format(time.time()))
            fun()
            print('结束时间:{}'.format(time.time()))
        
        return run_log
    
    def foo():
        for i in range(10):
            print(i)
    
    foo = log(foo)
    foo()
    
    
    

    现在我们改造了下代码,foo = log(foo)时,调用log()方法,内部定义了一个run_log()方法,然后返回给了foo,此时foo等于run_log,调用foo相当于调用run_log 这样,即实现了需要打印日志的需求,又可以不用去修改已有代码

    传参

    现在的foo()方法可以打印0到9数字,但是,由于业务需求变更,现在需要给foo()方法传递一个值,例如foo(100),就需要打印出0-99的数字,同时还要打印日志,所以我们需要再次优化代码

    import time
    
    
    def log(fun):
        def run_log(num):
            print('开始时间:{}'.format(time.time()))
            fun(num)
            print('结束时间:{}'.format(time.time()))
    
        return run_log
    
    
    def foo(num):
        for i in range(num):
            print(i)
    
    
    foo = log(foo)
    foo(100)
    
    

    根据之前的逻辑,我们已经知道新的foo()等于run_log(),所以我们给foo(100)传递100的值时,实际上等同于run_log(100),所以我们直接在def foo(num)中是接受不到的,我们需要在run_log(num)中接受到参数,传给fun(num),这样新的函数就可以接受参数了

    返回参数

    新的需求又来了,需要在foo()中返回一个所有数字的累加之和,而我们现有的foo函数实际上是run_log,所以我们再来改造一下代码

    import time
    
    
    def log(fun):
        def run_log(num):
            print('开始时间:{}'.format(time.time()))
            info = fun(num)
            print('结束时间:{}'.format(time.time()))
            return info
    
        return run_log
    
    
    def foo(num):
        add_num = 0
        for i in range(num):
            add_num += i
            print(i)
        return add_num
    
    
    foo = log(foo)
    x = foo(100)
    print(x)
    
    

    由于现在的foo()等同于run_log(),run_log()中的fun()相当于foo(),所以foo中返回的值传到了info中然后我们把info返回,x就可以接受到从run_log中传递出来的参数

    好了,到这里我们就实现了一个阉割版修饰器

    通用性

    假如需要你再给一个新的函数foo2打印日志, 代码如下

    import time
    
    
    def log(fun):
        def run_log(num):
            print('开始时间:{}'.format(time.time()))
            info = fun(num)
            print('结束时间:{}'.format(time.time()))
            return info
    
        return run_log
    
    
    def foo(num):
        add_num = 0
        for i in range(num):
            add_num += i
            print(i)
        return add_num
    
    
    def foo2(num, num2):
        add_num = 0
        for i in range(num, num2):
            add_num += i
            print(i)
        return add_num
    
    
    foo = log(foo)
    x = foo(100)
    print(x)
    
    

    由于我们的修饰器只能接收一个参数,而foo2需要两个参数,现有代码无法实现,所以我们要继续升级代码

    import time
    
    
    def log(fun):
        def run_log(*args,**kwargs):
            print('开始时间:{}'.format(time.time()))
            info = fun(*args,**kwargs)
            print('结束时间:{}'.format(time.time()))
            return info
    
        return run_log
    
    
    def foo(num):
        add_num = 0
        for i in range(num):
            add_num += i
            print(i)
        return add_num
    
    
    def foo2(num, num2):
        add_num = 0
        for i in range(num, num2):
            add_num += i
            print(i)
        return add_num
    
    
    foo = log(foo)
    foo2 = log(foo2)
    x = foo(100)
    x2 = foo2(50,100)
    print(x)
    print(x2)
    
    

    我们使用了*args,这样就可以接收任意数量的参数,可以满足我们的所有需求

    语法糖

    但是每次使用前都要写一个 foo = log(foo)这样的赋值操作,代码并不美观 不符合python的代码风格,所以python给提供了一种语法糖,可以用@log来替代,修改后代码如下

    import time
    
    
    def log(fun):
        def run_log(*args,**kwargs):
            print('开始时间:{}'.format(time.time()))
            info = fun(*args,**kwargs)
            print('结束时间:{}'.format(time.time()))
            return info
    
        return run_log
    
    @log
    def foo(num):
        add_num = 0
        for i in range(num):
            add_num += i
            print(i)
        return add_num
    
    @log
    def foo2(num, num2):
        add_num = 0
        for i in range(num, num2):
            add_num += i
            print(i)
        return add_num
    
    x = foo(100)
    x2 = foo2(50, 100)
    print(x)
    print(x2)
    
    

    我们只需要在定义函数时,在上面添加一句@修饰器名就相当于完成了函数名 = 修饰器名(函数名)这样的操作

    现在就已经是一个标准的修饰器了

    扩展

    同理,我们用js也可以写一个修饰器

    function log(fun) {
    	function run_log(...ags) {
    		console.log('==============')
    		let info = fun(...ags)
    		console.log('==============')
    		return info
    	}
    
    	return run_log
    }
    
    
    foo = log(foo)
    function foo(num, num1) {
    	let x = 0
    	for (let i = num; i < num1; i++) {
    		console.log(i)
    		x += i
    	}
    	return x
    }
    
    foo2 = log(foo2)
    function foo2(num) {
    	let x = 0
    	for (let i = 0; i < num; i++) {
    		console.log(i)
    		x += i
    	}
    	return x
    }
    
    
    foo(10, 100)
    foo2(10)
    
    
  • 相关阅读:
    去哪儿网门票数据爬虫更新
    每周进度总结12
    每日进度总结20
    每日进度总结19
    每日进度总结18
    每日进度总结17
    每日进度总结16
    每日进度总结15
    每日进度总结14
    每周进度总结11
  • 原文地址:https://www.cnblogs.com/WXGC-yang/p/13590507.html
Copyright © 2020-2023  润新知