ZMAN的学习笔记之Python篇:装饰器

  年前工作事务比较繁琐,我只能用零碎的时间继续学习Python,决定开一个系列的博文,作为自己深入学习Python的记录吧。名字也取好了,就叫《ZMAN的学习笔记之Python篇》~开篇是关于装饰器的,春节假期码的字哈哈~就让我们开始吧!

  本文的例子都是自己想的,如果不是很合适,请大家提出宝贵意见哈~谢谢啦!

一、为什么要用“装饰器”

  比如我们写了如下一段代码:

# 打印0~99
def func():
    for i in range(100):
        print(i)

  我们想要监测执行这个函数花费了多少时间,于是我们将这个函数改成了这样:

import time

# 打印0~99
def func():
    start = time.time()
    for i in range(100):
        print(i)
    end = time.time()
    print("耗时:%.4f" % (end - start))

  虽然达到了目的,但是我们却改变了原有的函数,而且如果有几十个不同的函数,都这样改动一下,工作量也是非常大的。

  使用了“装饰器”后,就能在不修改原函数的前提下,达到相同的功能。

二、什么是“装饰器”

  在Python中,函数是“对象”,而装饰器是函数,它的作用就是对已经存在的函数进行装饰。Python中的“装饰器”可以很好地解决那些有“面向切面编程”需求的问题。

  请看例子:

def deco(ex):
    print(‘func函数被调用前‘)
    ex()
    print(‘func函数被调用后‘)
    return ex

def func():
    print(‘func函数被调用‘)

func = deco(func)

>>>
func函数被调用前
func函数被调用
func函数被调用后

  我写了两个函数,将函数func作为参数传入deco函数,并将返回值赋给func变量。我们可以看成是func函数经过了deco的装饰~

  而这就是装饰器的概念了:装饰器可以说是封装器,让我们在被装饰的函数之前或之后执行一些代码,而不必修改函数本身。利用这点,我们可以做出许多酷炫的功能~

三、写第一个“装饰器”

  刚才我介绍了装饰器的概念,但这是一个“手工”的装饰器,并没有用到Python的装饰器语法,实际上,装饰器语法非常简单,看例子:

def deco(ex):
    def _deco():
        print(‘func函数被调用前‘)
        ex()
        print(‘func函数被调用后‘)
    return _deco

@deco
def func():
    print(‘func函数被调用‘)
    #return(‘OK‘)

func()

>>>
func函数被调用前
func函数被调用
func函数被调用后

  大家可以看到,我在定义函数func的上一行,加了一句“@deco”,这就是装饰器语法了,这样写了之后,能确保每次调用func函数都被deco函数装饰,是不是非常简单呀~~

四、让被装饰函数带上确定的参数

  如果被装饰函数带可以确定的参数,需要像下面这样对装饰器函数进行修改:

def deco(ex):
    def _deco(a, b):
        print(‘%s函数被调用前‘ % ex.__name__)
        c = ex(a, b)
        print(‘%s函数被调用后,结果为:%s‘ % (ex.__name__, c))

    return _deco

@deco
def func(a, b):
    print(‘func函数被调用,传入%s,%s‘ % (a, b))
    return a+b

func(1, 2)

>>>
func函数被调用前
func函数被调用,传入1,2
func函数被调用后,结果为:3

  这个例子的装饰器实现了:打印传入函数的名字、打印两个数字相加结果的功能。我们在原先的deco函数内又定义了一个函数_deco用来接收func函数中的参数。

五、让被装饰函数带上不确定的参数

def deco(ex):
    def _deco(*args, **kwargs):
        print(‘%s函数被调用前‘ % ex.__name__)
        c = ex(*args, **kwargs)
        print(‘%s函数被调用后,结果为%s‘ % (ex.__name__, c))

    return _deco

@deco
def func(a, b):
    print(‘func函数被调用,传入%s,%s‘ % (a, b))
    return a+b

@deco
def func2(a, b, c):
    print(‘func2函数被调用,传入%s,%s,%s‘ % (a, b, c))
    return a+b+c              

func(1, 2)
func2(1, 2, 3)

>>>
func函数被调用前
func函数被调用,传入1,2
func函数被调用后,结果为3
func2函数被调用前
func2函数被调用,传入1,2,3
func2函数被调用后,结果为6

  简单修改我们的代码,使用*args, **kwargs来捕捉不定量的传参,便实现了多个参数的求和。

六、让装饰器带上参数

def deco(ex):
    def _deco(func):
        def _deco2():
            print(‘%s函数被调用前,传入参数为:%s‘ % (func.__name__, ex))
            func()
            print(‘%s函数被调用后‘ % func.__name__)
        return _deco2
    return _deco

@deco(‘parameter1‘)
def func():
    print(‘func函数被调用‘)

func()

>>>
func函数被调用前,传入参数为:parameter1
func函数被调用
func函数被调用后

  如果要让装饰器带上参数,我们要在装饰器函数内部再多定义一层函数,用来接收装饰器的参数~大家可不要搞混了装饰器参数和函数的参数哟~

七、来个任性的:装饰器和被装饰函数都带参数

def deco(ex):
    def _deco(func):
        def _deco2(c, d):
            print(‘%s函数被调用前,装饰器参数为:%s‘ % (func.__name__, ex))
            x = func(c, d)
            if x > 3:
                x = x-ex
            else:
                x = x+ex
            print(‘%s函数被调用后,计算结果为:%d\n‘ % (func.__name__, x))
        return _deco2
    return _deco

@deco(3)
def func(a, b):
    print(‘func函数执行结果为:%s‘ % int(a+b))
    return(a+b)

func(3, 4)
func(1, 2)

>>>
func函数被调用前,装饰器参数为:3
func函数执行结果为:7
func函数被调用后,计算结果为:4

func函数被调用前,装饰器参数为:3
func函数执行结果为:3
func函数被调用后,计算结果为:6

  最初的func函数只是实现两个数字的相加,经过装饰后实现了对func返回的和的大小进行了分支处理:如果“两数的和大于3”,最后结果为“两数的和减去3”,否则最后结果为“两数的和加上3”。我在这个例子中使用的是“确定”的参数,大家可以自己更改哦~

八、同时使用多个装饰器

  之前的例子都是只用了一个装饰器,我们当然可以装饰多次啦~

def deco1(ex):
    def _deco1(string):
        print(‘deco1被调用前‘)
        string = ex(string)
        if ‘hello‘ in string:
            string = "You are my old friend."
        else:
            string = "You are my new friend."
        print(‘deco1被调用后,%s\n‘ % string)

        return string

    return _deco1

def deco2(ex):
    def _deco2(string):
        print(‘deco2被调用前‘)
        string = ex(string)
        if ‘ZMAN‘ in string:
            string = ‘hello, ‘ + string
        else:
            string = ‘Is your name ‘ + string + ‘?‘
        print(‘deco2被调用后,%s‘ % string)

        return string

    return _deco2

@deco1
@deco2
def func(string):
    print(‘func函数被调用‘)
    return string

func(‘ZMAN‘)
deco1(deco2(func(‘John‘)))

>>>
deco1被调用前
deco2被调用前
func函数被调用
deco2被调用后,hello, ZMAN
deco1被调用后,You are my old friend.

deco1被调用前
deco2被调用前
func函数被调用
deco2被调用后,Is your name John?
deco1被调用后,You are my new friend.

  在这个例子中,我们主要要关注装饰器调用的先后顺序,func(‘ZMAN‘)和deco1(deco2(func(‘ZMAN‘)))是等同的,这个调用顺序大家一看就明白了吧~

九、实际应用

  最后来个实际应用~好吧,我实在是绞尽脑汁了,写代码的时候正好在吃苹果,那就来个跟水果有关的实例吧(别打我 - -!)

#综合运用:简单地检测函数传参是否合法

def deco(ex):
    def _deco(*args, **kwargs):
        print(‘***%s函数被调用前***‘ % ex.__name__)
        if args:
           if not isinstance(args[0], str):
               print(‘★店名参数错误:%s‘ % args[0])
           if not(isinstance(args[1], int) and args[1]>0):
               print(‘★员工参数错误:%s‘ % args[1])

        else:
            print(‘★未传入店名和员工数信息!‘)

        if kwargs:
            for i in kwargs:
                if not ((isinstance(kwargs[i], int)
                    or isinstance(kwargs[i], float))
                    and kwargs[i]>0):
                    print(‘★水果单价参数错误:%s:%r‘ % (i, kwargs[i]))
        else:
            print(‘★未传入水果单价信息!‘)

        a = ex(*args, **kwargs)
        print(‘***%s函数被调用后***\n‘ % ex.__name__)

    return _deco

@deco
# 假设传入几家水果店的名称、员工数以及水果单价。店名为字符,员工数为正整数,单价为正数
def func(*args, **kwargs):
    print(‘***函数func被调用***‘)
    brief = args
    detail = kwargs
    return(brief, detail)

func(‘水果之家‘, -4, apple=3.5, strawberry=6, orange=3, cherry=8.5,)
func(123, 8, apple=3, orange=2,)
func(‘天然果园‘, 0.2, )
func()

>>>
***func函数被调用前***
★员工参数错误:-4
***函数func被调用***
***func函数被调用后***

***func函数被调用前***
★店名参数错误:123
***函数func被调用***
***func函数被调用后***

***func函数被调用前***
★员工参数错误:0.2
★未传入水果单价信息!
***函数func被调用***
***func函数被调用后***

***func函数被调用前***
★未传入店名和员工数信息!
★未传入水果单价信息!
***函数func被调用***
***func函数被调用后***

  代码有点长,但是只要大家耐心看,其实还是挺简单的,没有什么花里胡哨的东西。这个装饰器用来检测传参是否合法~

十、小结

  第一篇洋洋洒洒那么多个例子,终于写完了!利用“装饰器”,我们无须改写原函数,就能对它进行功能扩充,比如计时、检测传参、记录日志等等。就比如我们有一把枪,我们可以给它加上消音器,又或者是刺刀…不用的时候就拿掉,还是原来的枪~~

  (本文难免有写错或不足的地方,希望大家不吝赐教哦~谢谢!)

时间: 2024-10-07 06:31:15

ZMAN的学习笔记之Python篇:装饰器的相关文章

ZMAN的学习笔记之Python篇:命令行解析

ZMAN的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:ZMAN  (http://www.cnblogs.com/zmanone/) 在Python中,对命令行的解析方式不唯一,本文将介绍两种方法:一种是用sys.argv手动设置,另一种是用argparse模块. 一.sys.argv是什么 首先看一个例子: import sys print(len(sys.argv)) for arg in sys.argv: print(arg) 将

ZMAN的学习笔记之Python篇:函数可变长参数

ZMAN的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 这次来聊聊Python中函数的“可变长参数”,在实际中经常会用到哦~  一.什么是“可变长参数” “可变长参数”就是向一个函数传入不定个数的参数.比如我写一个函数:传入一个学生参加各科目考试的成绩,求平均分,如两个学生分别传入(92, 91, 88)和(88, 95),因为每个学生参加的考试个数不同,因此传入的参数个数也就不同了,遇到这种情况,我们在定义函数的时候,可以使用“可变长参数”. 二.在定义函数时使用“可变长参数

Python学习笔记__4.4章 装饰器(添加额外功能)

# 这是学习廖雪峰老师python教程的学习笔记 1.概览 装饰器可以帮助我们为已经存在的对象添加额外的功能 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象. 装饰器经常用于有切面需求的场景,比如:插入日志.性能测试.事物处理.缓存.权限校验等场景. 1.1.为now函数 加一行日志 # 定义now函数 def now(): print('2018-5-8') # 编辑decorator def log(func):

Python学习笔记(十一)装饰器

摘抄:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000#0 本文章完全用来个人复习学习,侵删: 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25') ... >

Python学习笔记(2)装饰器

1,.概念 装饰器英文名Decorator,装饰器的作用就是为已经存在的对象添加额外的功能.总的来说,装饰器其实就是一个函数,一个用来包装函数的函数,所以他的参数是被修饰的函数对象,返回一个修改之后的函数对象,将其重新赋值原来的标示符,并永久丧失对原始函数对象的访问. 2.装饰器语法 1.def deco(func): 2. print func 3. return func 4[email protected] 5.def foo():pass 6.foo() 第一个函数deco是装饰函数,它

python学习笔记(5)--迭代器,生成器,装饰器,常用模块,序列化

生成器 在Python中,一边循环一边计算的机制,称为生成器:generator. 如: 1 >>> g = (x * x for xin range(10)) 2 >>> g3 <generator object <genexpr> at 0x1022ef630> 此处g就是一个生成器. 迭代器 我们已经知道,可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str等: 一类是gene

python学习笔记-(八)装饰器、生成器&amp;迭代器

本节课程内容概览: 1.装饰器 2.列表生成式&迭代器&生成器 3.json&pickle数据序列化 1. 装饰器 1.1 定义: 本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能 1.2 装饰器原则: 1)  不能修改被装饰函数的源代码: 2)  不能修改被装饰函数的调用方式: 1.3 实现装饰器知识储备: 1.3.1 函数即“变量” 定义一个函数相当于把函数体赋值给了函数名 变量可以指向函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Python 3 学习笔记(六)----装饰器

一.定义 装饰器本质是函数,装饰其他函数,就是为其它函数添加附加功能 二.装饰器原则 1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 三.实现装饰器的必要知识 1.函数即是变量 1 # def foo(): 2 # print("in the foo") 3 # bar() #bar未定义 4 # foo() 5 6 7 # def bar(): 8 # print("int the bar") 9 # def foo(): 10 # prin

Python学习笔记(yield与装饰器)

yeild:返回一个生成器对象: 装饰器:本身是一个函数,函数目的装饰其他函数(调用其他函数) 功能:增强被装饰函数的功能 装饰器一般接受一个函数对象作为参数,以便对其增强 @原函数名  来调用其他函数 递归:递归需要边界条件,递归前进段和递归返回段: 10*9*8*7*6*5*4*3*2*1 10*9 10*(10-1)*(10-1)-1) 协程: 函数的设计规范: 耦合性: (1)通过参数接受输入,以及通过return产生输出以保证函数的独立性: (2)尽量减少使用全局变量进行函数间通信: