Python基础(装饰器)

代码的编写和软件的开发,都应该遵循开放封闭原则。

开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。其核心思想是:

对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。

对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。

而装饰器(就是函数)的作用就是为已经存在的对象添加额外的功能。

此篇文章主要介绍装饰器的五种使用情况。

需求场景:

让一个已经开发完成的功能在执行之前,先执行某些操作。

一、基本用法

原函数:

def func1():

print ‘old func1‘

func1()

执行结果:

old func1

定义装饰器:

def w1(func):    #这里参数func的值就是被装饰的函数的函数名

def _w1():   #定义一个新的函数

print ‘Begin new func %s()‘%func.func_name  #装饰器中新加入的操作

func()  #执行完新加入操作后开始执行原函数

return _w1   #返回被重新装饰过的函数,函数名为_w1

使用装饰器装饰原函数:

@w1        #装饰器用法,@+装饰器函数名,放在需要被装饰的函数上面

def func1():

print ‘old func1‘

func1()

执行结果:

Begin new func func1()

old func1

二、动态参数,可以装饰带有N个(N>=0)参数的函数

def w2(func):

def _w2(*args,**kwargs):    #可接受任意参数的函数

print ‘Begin new func %s()‘%func.func_name

func(*args,**kwargs)

return _w2

@w2

def func1():        #不带参数的函数

print ‘old func1‘

@w2

def func2(*args,**kwargs): #带任意参数的参数

print ‘old func2,arg is %s‘%args

func1()    #执行不带参数的函数

func2(‘test‘) #执行带参数的函数,并赋值一个test参数

执行结果:

Begin new func func1()

old func1

Begin new func func2()

old func2,arg is test

三、被装饰的函数带有return值

错误写法:

def w3(func):

def _w3(*args,**kwargs):

print ‘Begin new func %s()‘%func.func_name

func(*args,**kwargs)

return _w3

@w3

def func3(*args,**kwargs):

print ‘old func3,arg is %s‘%args

return ‘done‘    #定义函数的返回值为done

re = func3(‘test‘)    #获取函数的返回值

print re        #打印函数的返回值

执行结果:

Begin new func func3()

old func3,arg is test

None    #结果函数的返回值为None

正确写法:

def w3(func):

def _w3(*args,**kwargs):

print ‘Begin new func %s()‘%func.func_name

return func(*args,**kwargs)

return _w3

@w3

def func3(*args,**kwargs):

print ‘old func3,arg is %s‘%args

return ‘done‘

re = func3(‘test‘)

print re

执行结果:

Begin new func func3()

old func3,arg is test

done    #得到正确的返回值,请自行查看两种写法的差别。

四、多个装饰器装饰同一个函数(多个装饰器的情况下,从里往外(下往上)装饰,装饰完成后,从外往里(上往下)执行)

应用场景:同一个函数希望扩展两个完全不一样的功能,比如一个验证功能,一个记录日志的功能。

用一个例子进行说明:

def first(func):    #装饰器1

print ‘%s() was post to first()‘%func.func_name

def _first(*args,**kw):

print ‘Call the function %s() in _first().‘%func.func_name

return func(*args,**kw)

return _first

def second(func):    #装饰器2

print ‘%s() was post to second()‘%func.func_name

def _second(*args,**kw):

print ‘Call the function %s() in _second().‘%func.func_name

return func(*args,**kw)

return _second

@first     #装饰器1

@second    #装饰器2

def test(*args,**kwargs):

print ‘test() args -->‘,args

test(‘123‘)

执行结果:

test() was post to second()

_second() was post to first()

Call the function _second() in _first().

Call the function test() in _second().

test() args --> (‘123‘,)

逐条解释:

test() was post to second()     #由于装饰器second在test函数上面,所以会先用装饰器second装饰test,这时候装饰器second的参数是test,执行后的返回值是_second函数,里面的func变量值是test函数

_second() was post to first()   #由于_second函数上还有一个装饰器first,所以会用装饰器first装饰_second,这时候装饰器first的参数是_second, 执行后的返回值是_first函数,里面的func变量值是_second函数

Call the function _second() in _first().    #所有装饰器装饰完成,开始执行,这里会先执行_first函数,等于在里面执行_second()

Call the function test() in _second().  #开始执行_second函数,等于在里面执行test()

test() args --> (‘123‘,)   #test函数执行的结果

五、多层装饰器,(带参数的装饰器、不要和第二种情况搞混)

应用场景:当希望使用装饰器装饰函数时,装饰器内部调用的方法是可定义的,比如装饰A函数时,内部调用AA方法,装饰B函数时,内部调用BB方法。

用一个例子进行说明:

def Before(request,kargs):

print ‘before -->‘,request

def After(request,kargs):

print ‘after <--‘,kargs

def Filter(before_func,after_func):    #第一层装饰器

def outer(main_func):    #第二层装饰器

def wrapper(request,kargs):  #第二层装饰器定义的函数

before_result = before_func(request,kargs)

if(before_result != None):

return before_result;

main_result = main_func(request,kargs)

if(main_result != None):

return main_result;

after_result = after_func(request,kargs)

if(after_result != None):

return after_result;

return wrapper    #第二层装饰器返回的函数

return outer    #第一层装饰器返回的函数,也就是另一个装饰器

@Filter(Before, After)

def Index(request,kargs):

print ‘index‘

Index(‘begin‘,‘end‘)

执行结果:

before --> begin

index

after <-- end

执行过程:

1、解释器读取到装饰器@Filter(Before, After),开始执行Filter(Before, After)函数

2、进入Filter函数执行,并传入参数‘Before, After‘,此时Filter函数中参数before_func=Before,参数after_func=After。

继续往下执行,函数中定义了一个outer函数,由于未调用该函数,所以不执行该函数,继续往下执行

3、Filter函数return了outer函数作为本次执行的返回值

4、根据Filter函数执行的返回值创建了新的装饰器@outer

5、开始执行outer函数,此时其参数main_func的值为原函数Index,也就是main_func=Index

6、outer函数中定义了另一个函数wrapper,其参数的值是原函数Index传入的参数值,由于未调用该函数,所以不执行该函数,继续往下执行

7、outer函数return了wrapper函数作为本次执行的返回值

8、原函数Index被重新赋值等于wrapper函数,也就是Index=wrapper

9、开始执行新的Index函数(即wrapper函数)也就是wrapper(‘begin‘,‘end‘)

10、执行时会先执行before_func(request,kargs),也就是Before(‘begin‘,‘end‘)

11、再执行main_func(request,kargs),也就是Index(‘begin‘,‘end‘)

12、最后执行after_func(request,kargs),也就是After(‘begin‘,‘end‘)

执行完成。

时间: 2024-11-05 02:17:43

Python基础(装饰器)的相关文章

python基础—装饰器

python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a) print(b) 123 <function foo at 0x000001608E2B97B8> 解释:把函数foo赋值给a和b,a 赋值的是调用后的函数,变量的值就是返回值.b 赋值的是调用前的函数,所以b 就是那个赋值的函数.函数本身+(),就是调用. callable(a) False

python基础-装饰器和偏函数

一.装饰器 1.概念:装饰器是一个闭包(内层函数引用外层函数的非全局变量,这个内层函数就可称之为闭包),把一个函数当做参数返回一个替代版的函数,本质上就是一个返回函数的函数. 2.作用:在不修改源代码的基础上,扩展代码的使用. 3.理解装饰器 #不带参数的源函数 def fun1(): print("I love python") fun1() #若我想在原来的基础上,先输出一行的*号,我们可以重新写一个函数 def fun2(): print("***********&qu

python基础===装饰器@property

以下来自Python 3.6.0 Document: class property(fget=None, fset=None, fdel=None, doc=None) Return a property attribute. fget is a function for getting an attribute value. fset is a function for setting an attribute value. fdel is a function for deleting an

python基础---装饰器

1,装饰器: 1)为什么要用装饰器:因为你开发的程序一旦上市,就要遵守源代码开放并且尽量不能修改源代码,函数的调用方式也尽量不要修改,新的需求来了,每一       款软件都是需要更新的,在不修改源代码,不修改函数调用方式,同时还要增加新的功能,怎么实现呢?所以有了装饰器,来满足我们的条件. 2)什么是装饰器:顾名思义,装饰就是修饰,器相当于函数 3)装饰器定义:其本质就是一个函数,功能是为其他函数添加新的一个功能. 2,举例: 1) 现在来建立一个最简单的函数,这组函数值打印"welcome

【转】详解Python的装饰器

原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def say_hello(): print "hello!" def say_goodbye(): print "hello!" # bug here if __name__ == '__main__':

Python学习---装饰器的学习1210

装饰器的基础 学习前提: 作用域 + 函数的理解 + 闭包  [学习,理解] 代码编写原则: 对修改开放对扩展开放 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用:经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权限校验等应用场景.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用. 装饰器作用:装饰器感觉就像是内部函数的

详解Python的装饰器

Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def say_hello(): print "hello!" def say_goodbye(): print "hello!" # bug here if __name__ == '__main__': say_hello() say_goodbye() 但是在实际调用中,我们

进阶Python:装饰器 全面详解

进阶Python:装饰器 前言 前段时间我发了一篇讲解Python调试工具PySnooper的文章,在那篇文章开始一部分我简单的介绍了一下装饰器,文章发出之后有几位同学说"终于了解装饰器的用法了",可见有不少同学对装饰器感兴趣.但是那篇文章主要的目的是在介绍PySnooper,所以没有太深入的展开讲解装饰器,于是在这里就详细的介绍一些装饰器的使用. 装饰器是Python中非常重要的一个概念,如果你会Python的基本语法,你可以写出能够跑通的代码,但是如果你想写出高效.简洁的代码,我认

尝试自己的Perl语言的包 TCP协议的再包装起到类似python语言装饰器的效果

#!/usr/bin/perl # Filename: BuildSocketTCP.pm # #   Copyright 2012 Axxeo GmbH #   Licensed under the Apache License, Version 2.0 (the "License"); #   you may not use this file except in compliance with the License. #   You may obtain a copy of t

尝试自己的Perl语言的包 UDP协议的再包装起到类似python语言装饰器的效果

#!/usr/bin/perl # Filename: BuildSocketUDP.pm # #   Copyright 2012 Axxeo GmbH #   Licensed under the Apache License, Version 2.0 (the "License"); #   you may not use this file except in compliance with the License. #   You may obtain a copy of t