浅谈Python装饰者模式与其他静态语言(C++,Java)装饰者的区别

装饰器模式

有时候我们可能要对一些函数添加一些功能,但又不想,也没必要破坏它的内部功能,比如测执行时间,单元测试,怎么办呢?没关系,Python中内置了一种新语法,允许给函数加上一层封装,称为装饰器函数,调用目标函数将把外层装饰器函数的上下文也一并执行出来,这种执行方式的优点在于,如果新增的功能不需要了,只需要删除装饰器函数即可,原有的目标函数不会受到任何影响。

一个典型的装饰器实现如下

import time
from functools import wraps
def decorator(fn):
    @wraps(fn) #使得终端调用func.__name__ == func而不是wrapper
    def wrapper():
        start_time = time.time()
        fn()
        end_time = time.time()
        print("exec time: %s ms" % (end_time - start_time));
    return wrapper;

@decorator #相当于decorator(func)
def func():
    print("2023-3-7")
    
if __name__ == '__main__':
    func()
""" 
	output:
    2023-3-7
	exec time: 0.0 ms

 """

python能够实现这种设计的原因是,函数在python中属于和List, dict等类型同等的对象,在函数内定义函数本质也是定义对象,因此上面的decorator函数可看作定义并返回了一个wrapper的对象,这种在函数内部定义的被称为闭包函数,闭包函数正是Python实现装饰器的底层基础。

如果换到C++,虽然lamada也能承担闭包的功能,但是没法像使用原有函数一样使用装饰后的函数。

#include <iostream>
#include <time.h>
#include <functional>
using namespace std;
std::function<void()> decorator(std::function<void()> fn)
{
    auto wrapper = [&](){
        clock_t start_time = clock();
        fn();
        clock_t end_time = clock();
        cout << "exec time: " << end_time - start_time << "ms" << endl;
    };
    return wrapper;
}

void func()
{
    printf("2023-3-7\n");
}

int main(){
    /* 
        output:
            2023-3-7
            exec time: 2ms
     */
    decorator(func)();
}

由于python支持内部定义闭包,因此如果装饰器本身要传入参数,还可以设计成这种三层的闭包:

import time
from functools import wraps
def log(text):
    def decorator(fn):
        @wraps(fn) #使得终端调用func.__name__ == func而不是wrapper
        def wrapper():
            start_time = time.time()
            fn()
            end_time = time.time()
            print("text: %s exec time: %s ms" % (text, end_time - start_time));
        return wrapper
    return decorator

@log('test') #注意可以通过@语法直接向装饰器传参, 这里相当于 log('test')(func)
def func():
    print("2023-3-7")


if __name__ == '__main__':
    func()

翻译成C++应该是这样,C++11的auto真的省了很多类型推断的事情。

#include <iostream>
#include <time.h>
#include <functional>
using namespace std;
typedef std::function<void()> CallBack;
auto log(string text){
    auto decorator = [&](CallBack fn) -> CallBack{
        auto wrapper = [&]() -> void {
            clock_t start_time = clock();
            fn();
            clock_t end_time = clock();
            cout << "text: " << text << " exec time: " << end_time - start_time << "ms" << endl;
        };
        return wrapper;
    };
    return decorator;
}

void func()
{
    printf("2023-3-7\n");
}

int main()
{
    /* 
        output:
            2023-3-7
            text: text exec time: 1ms
     */
    log("test")(func)();

}

总结:在设计模式的概念上, Python通过语法,直接在函数层面实现了装饰器,而像C++,Java这样的静态类型语言欲实现只能通过多态+组合的手法在类层面实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值