详解Python装饰器

装饰器的难点:在梳理了装饰器的整个内容之后,我认为难点不是装饰器本身,而是直接调用被装饰的函数,让人无法理解背后究竟发生了什么。

一、引出装饰器概念

引入问题:  定义了一个函数,想在运行时动态的增加功能,又不想改动函数本身的代码?

示例:
希望对下列函数调用增加log功能,打印出函数调用:

def f1(x): return x*2
def f2(x): return x*x
def f3(x): return x*x*x


方法一:直接修改原函数的定义

def f1(x): 
    print("call f1") 
    return x*2

def f2(x): 
    print("call f2") 
    return x*x

def f3(x): 
    print("call f3")
    return x*x*x


方法二:通过高阶函数返回新函数

思考:高阶函数

(1)、接受函数作为参数

(2)、返回函数

(3)、因此:通过接收一个函数,内部对其包装,然后返回一个新函数,这样子动态的增强函数功能

def f1(x): return x*2
      
def new_fun(f):
    """ 装饰器函数 """
    def fun(x):
        print("call " + f.__name__)
        return f(x)
    return fun

new_fun(f1)(10)

方法三:真正的装饰器

Python内置的 @ 语法就是为了简化装饰器的使用。

@new_fun代表的意思:调用new_fun函数,参数是@所在行下面的函数

@new_fun
def f1(x): return x*2


@new_fun
def f2(x): return x*x


@new_fun
def f3(x): return x*x*x
      
f1(10)
f2(100)
f3(1000)


f1(10)的调用方式等价于new_fun(f1)(10), new_fun(f1)返回的是装饰器内部函数fun,即fun(10). 整个功能的完成被分成三部分:装饰器函数执行,返回装饰器内部函数;装饰器内部函数执行,执行logging功能;在执行内部函数的同时或者执行完内部函数之后,执行被装饰函数f(x)。因此我们也容易看出整个装饰器就是三部分:装饰器函数,装饰器内部函数,被装饰函数。


三、装饰器作用:可以极大简化代码,避免每个函数编写重复性的代码

(1)、打印日志:@log,如本文所举的例子

(2)、检测性能:@performance,例如机器学习训练模型,监测多个模型,多个函数运行时间。


四、装饰器函数三步走

(1)、定义自己先要执行的函数

(2)、定义装饰器函数

def new_fun(要执行的函数f):
    def fun(要执行的函数的参数x):
        添加函数功能
        return f(x)
    return fun

(3)、装饰器进行修饰

# -*- coding: utf-8 -*-
# 装饰器监测函数的调用和性能

def print_log(f):
    """ 装饰器函数: 监测函数的调用 """
    def fun(x):
        print(f.__name__ + " is called.")
		
		# 可以不返回, 直接在此处执行f(x)
        return f(x)
    return fun
    
@print_log
def sort_fun(num_list):
    """ 排序函数 """
    return sorted(num_list)


if __name__ == "__main__":
    num_list = sort_fun(list(range(100))*100)


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值