Python学习笔记:装饰器

时间:2023-11-24 14:08:26

Python 装饰器的基本概念和应用

  • 代码编写要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
  1. 封闭:已实现的功能代码块
  2. 开放:对扩展开发

装饰器是 Python 高阶函数的语法糖,可以为已经存在的对象添加额外的功能,比如:

  1. 引入日志
  2. 函数执行时间统计
  3. 执行函数前预备处理
  4. 执行函数后清理功能
  5. 权限校验等场景
  6. 缓存

Python 装饰器的基本实现

装饰器的例程:

 #!/usr/bin/env python3
#-*- coding:utf-8 -*-
#File Name:04_decorator_simple.py
#Created Time:2019-01-09 15:24:38 import time def timefun(func):
# wrapped_fun 即为闭包, func 为要装饰的函数
def wrapped_fun():
start_time = time.time()
func()
end_time = time.time()
print("%s\t运行用时 %f s" % (func.__name__, end_time - start_time))
return wrapped_fun # 返回内部函数的引用 def foo1():
for i in range(10000):
pass @timefun # 相当于 foo = timefun(foo)
def foo():
for i in range(100000):
pass if __name__ == "__main__":
foo1 = timefun(foo1)
foo1()
foo()

装饰器例程

foo1    运行用时 0.000491 s
foo 运行用时 0.002976 s

装饰器例程的运行结果

运行过程分析见下图:

Python学习笔记:装饰器

Python 装饰器实现的基础为闭包,其会在闭包中调用目标函数,关于闭馆的详细内容,请参考 Python 学习笔记:闭包

Python 装饰器的使用

多个装饰器

 #!/usr/bin/env python3
#-*- coding:utf-8 -*-
#File Name:05_decorator_multi.py
#Created Time:2019-01-09 15:55:31 def make_body(func):
"""添加 body"""
def wrapped():
return "<b>" + func() + "</b>"
return wrapped def make_italic(func):
"""设置为斜体"""
def wrapped():
return "<i>" + func() + "</i>"
return wrapped # 相当于 make_body(make_italic(foo))
@make_body
@make_italic
def foo():
return "Hello World" def foo1():
return "Hello Python" if __name__ == "__main__":
print(foo())
foo1 = make_body(make_italic(foo1))
print(foo1())

01 多个装饰器

<b><i>Hello World</i></b>
<b><i>Hello Python</i></b>

01 多个装饰器——运行结果

多个装饰器的运行过程分析:

Python学习笔记:装饰器

含有不定长参数

 #!/usr/bin/env python3
#-*- coding:utf-8 -*-
#File Name:06_decorator_multi_var.py
#Created Time:2019-01-09 16:20:30 from time import ctime def timefun(func):
def wrapped_func(*args, **kwargs):
print("%s called at %s" % (func.__name__, ctime()))
print("wrapped_func: ", end="")
print(args, kwargs)
func(*args, **kwargs) # 拆包
return wrapped_func @timefun
def foo(a,b,*args, **kwargs):
print("foo: %s, %s, %s, %s" %(a, b, args, kwargs)) if __name__ == "__main__":
foo(1,2,3,4,5, tmp=2)

02 含有不定长参数

foo called at Wed Jan  9 16:32:48 2019
wrapped_func: (1, 2, 3, 4, 5) {'tmp': 2}
foo: 1, 2, (3, 4, 5), {'tmp': 2}

02 含有不定长参数——运行结果

带有返回值

 #!/usr/bin/env python3
#-*- coding:utf-8 -*-
#File Name: 07_decorator_multi_retrun.py
#Created Time:2019-01-09 16:20:30 from time import ctime def timefun(func):
def wrapped_func(*args, **kwargs):
print("%s called at %s" % (func.__name__, ctime()))
print("wrapped_func: ", end="")
print(args, kwargs)
return func(*args, **kwargs) # 此处如何没有 return,则26行会输出 None
return wrapped_func @timefun
def foo(a,b,*args, **kwargs):
print("foo: %s, %s, %s, %s" %(a, b, args, kwargs))
return "Hello world!" if __name__ == "__main__":
print(foo(1,2,3,4,5, tmp=2))

03带有返回值

foo called at Wed Jan  9 16:38:05 2019
wrapped_func: (1, 2, 3, 4, 5) {'tmp': 2}
foo: 1, 2, (3, 4, 5), {'tmp': 2}
Hello world!

03带有返回值——运行结果

装饰器中设置外部变量

 #!/usr/bin/env python3
#-*- coding:utf-8 -*-
#File Name: 08_decorator_outside_var.py
#Created Time:2019-01-09 16:20:30 def timefun_arg(outside_var="Hello"):
def timefun(func):
def wrapped_func(*args, **kwargs):
print("wrapped_func: %s" % outside_var)
return func(*args, **kwargs)
return wrapped_func
return timefun @timefun_arg()
def foo(a,b,*args, **kwargs):
return "foo: Hello world!" @timefun_arg("Python") # 相当于 foo1 = timefun_arg("Python")(foo1)
def foo1(a,b,*args, **kwargs):
return "foo1: Hello world!" if __name__ == "__main__":
print(foo(1,2,3,4,5, tmp=2))
print(foo1(1,2,3,4,5, tmp=2))

04 装饰器中设置外部变量

定义多层函数,相当于双层的装饰器。

wrapped_func: Hello
foo: Hello world!
wrapped_func: Python
foo1: Hello world!

04装饰器中设置外部变量——运行结果

类装饰器

 #!/usr/bin/env python3
#-*- coding:utf-8 -*-
#File Name:09_decorator_class.py
#Created Time:2019-01-09 16:53:33 class Test(object):
def __init__(self, func):
print("******初始化******")
print("Called by %s." % func.__name__)
self.func = func def __call__(self):
return self.func() @Test # 相当于 foo = Test(foo)
def foo():
return "Hello world!" def foo1():
return "Hello python!" if __name__ == "__main__":
print(foo())
foo1 = Test(foo1)
print(foo1())

05 类装饰器

类对象借助 __call__()  魔术方法,即可实现相应的类装饰器

******初始化******
Called by foo.
Hello world!
******初始化******
Called by foo1.
Hello python!

05 类装饰器运行结果