python基础学习-装饰器详解

神奇的装饰器

装饰器,是Python的很重要的一个功能。如果有Java基础的童鞋会晓得,有个东西叫注解。他们是类似的东西。
python的装饰器,取决于以下几个特点:

  1. 函数可以作为参数
  2. 函数的返回值可以是参数
  3. python闭包特性
  4. 函数可以像变量一样赋值使用
    首先我们来先写一个hello world
    def hello_world(){
        print('hello the world!!')
    }
    
    然后,我们想要在进入之前,打印一下时间。怎么办呢,我们可以这么办。
    from date.datetime import datetime
    def inter_time() {
        print("进入时间:{d_time}".format(d_time=datetime.now()));
        hello_world();
    }
    
    但是这样写没有办法通用,如果我想要在其他函数上也加上这个进入时间的话。很麻烦。我们可以利用python的函数可以作为参数传递的性质来解决这个问题。
    from date.datetime import datetime
    def inter_time(c_func) {
        print("进入时间:{d_time}".format(d_time=datetime.now()));
        # 通过函数名加()的方式,来执行函数
        c_func();
    
    我们可以通过 inter_time(test_func)的方式,来实现在test_func执行之前,输出时间了。但是有个问题,我并不想把我的函数都变成inter_time(test_func)来实现,我还是想用我自己的名字来执行(test_func())。我们可以通过python的闭包和函数可以最为返回值的性质来实现。
    from date.datetime import datetime
    def inter_time(c_func) {
        # 内函数
        def show_time() {
             print("进入时间:{d_time}".format(d_time=datetime.now()));
             # 通过函数名加()的方式,来执行函数
             c_func();
        }
        return show_time
    
    注意,inter_time的返回值是一个函数,不是一个函数执行的结果,因为它的函数名后面没有括号。你可以这样使用它test_func = inter_time(test_func)。这个执行结果,其实就是把test_func函数重新赋值成了show_time。这样你就可以通过执行test_func()来实现我们输出进入时间的目的了。那其实我们已经实现了我们的装饰器了,只不过这种使用方式还不是很方便。我们可以用这种方式。
    # 通过@加装饰器名称,放在需要被装饰的函数前面
    # 就可以实现装饰器的使用
    # 等效于 test_func = inter_time(test_func)
    @inter_time
    def test_func():
        pass
    
    大体上我们的装饰器就好了,可以用了。但是还是有些细节需要处理的。比如,你想要打印test_func.name,用来做其他处理。但是你发现,你打印出来的并不是test_func,而是show_time。这就麻烦了,怎么办呢。其实django内置了一个装饰器来解决这个问题,就是@wraps,我们修改一下我们的装饰器。
    from date.datetime import datetime
    def inter_time(c_func) {
        # 内函数
        # 内置装饰器wraps
        # 它做了啥呢。其实就是将c_func的内置属性,复制到了show_time上
        # 这样,我们输出test_func.__name__的时候,就是test_func本身的属性值了
        @wraps(c_func)
        def show_time() {
             print("进入时间:{d_time}".format(d_time=datetime.now()));
             # 通过函数名加()的方式,来执行函数
             c_func();
        }
        return show_time   
    
    但是大家有没有注意,这个内置装饰器wraps它竟然带参数。哇,这么神奇,我也想要。那怎么办呢,我也带一个呗。不急,在带参数之前,我们首先试试看,装饰器带括号后,是什么情况。
    @inter_time()
    def test_func():
        pass
    
    完了,报错了。TypeError: inter_time() missing 1 required positional argument: 'func'。为什么的,我们将装饰器转换成函数调用的方式,你就明白了。带了括号的装饰器,调用过程是这样的。
    test_func = inter_time()(test_func)
    
    对你没看错,带括号之后他会自己首先执行一次,然后在对执行结果在执行一次。那怎么办呢,我们可以在我们原有的装饰器外面,在加一层函数。
    from date.datetime import datetime
    def inter_time(c_from) :
        def the_time(func) :
            @wraps(func)
             def show_time() :
                 print('来源:{c_from}.format(c_from=c_from))
                 print("进入时间:{d_time}".format(d_time=datetime.now()));
                 # 通过函数名加()的方式,来执行函数
                 c_func()  
            return show_time
        return the_time
    
    这个时候,我们就可以使用带有参数的装饰器了。
    # 相当于 test_func = inter_time('sss')(test_func)
    @inter_time('xxx')
    def test_func():
        pass
    
    最后一个问题,如果我的test_func有参数怎么办,我该怎么传过去呢。这个很简单,你只需要在装饰器里面带上参数,并使用就行了。
    from date.datetime import datetime
    def inter_time(c_from) :
        def the_time(func) :
            @wraps(func)
             def show_time(*args, **kwargs) :    # 这里使用了参数
                 print('来源:{c_from}.format(c_from=c_from))
                 print("进入时间:{d_time}".format(d_time=datetime.now()));
                 # 通过函数名加()的方式,来执行函数
                 # 这里使用了参数
                 c_func(*args, **kwargs)  
            return show_time
        return the_time
    
    好啦,你可以开始设计机自己的装饰器了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落笔成名

客官,辛苦则个

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值