Python基础05 - 装饰器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python基础05 - 装饰器相关的知识,希望对你有一定的参考价值。

@@@文章内容参照老男孩教育  Alex金角大王,武Sir银角大王@@@

函数即对象

  在python中,函数和我们之前的[1,2,3],‘abc‘,8 等一样都是对象,而且函数是最高级的对象(对象是类的实例化,可以调用相应的方法,函数是包含变量对象的对象。)

高阶函数

嵌套函数及闭包

1 def func():
2     x = 1
3     def foo():
4         print(x)
5     return foo
6 
7 a = func()
8 a()

闭包(closure)是函数式编程的重要的语法结构

  定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包

如上实例,foo就是内部函数,foo里引用了外部作用域的变量x(x在外部作用域func里面,不是在全局作用域),则这个内部函数foo就是一个闭包。

代码的开放封闭原则

  软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

  • 封闭:已实现的功能代码块不应该被修改
  • 开放:对现有功能的扩展开发

装饰器概念

装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

 1 import time
 2 # 业务生产中大量调用的函数
 3 def foo():
 4     print(hello foo)
 5 foo()
 6 # 现在有一个新的需求,希望可以记录下函数的执行时间,于是在代码中添加日志代码
 7 def foo():
 8     start_time = time.time()
 9     time.sleep(2)
10     print(hello foo)
11     stop_time =time.time()
12     print(spend %s %(stop_time - start_time))
13 
14 foo()
15 
16 # bar()、bar2()也有类似的需求,怎么做?再在bar函数里调用时间函数?
17 # 这样就造成大量雷同的代码,为了减少重复写代码,我们可以这样做,重新定义一个函数:专门设定时间
18 def show_time(func):
19     start_time = time.time()
20     func()
21     stop_time = time.time()
22     print(spend %s %(stop_time - start_time))
23 
24 def foo():
25     time.sleep(2)
26     print(hello foo)
27 
28 show_time(foo) 

逻辑上不难理解,而且运行正常。但是这样改变了调用方式,容易被人投诉,因为我们每次都要将一个函数作为参数传递给show_time函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑进,执行foo(),但是现在不得不改成show_time(foo)。那么有没有更好的方式呢?当然有,答案就 是装饰器。

简单装饰器

 1 import time
 2 def show_time(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         stop_time = time.time()
 7         print(spend %s %(stop_time - start_time))
 8 
 9     return wrapper
10 
11 # @符号是装饰器的语法堂,在定义函数的时候使用,避免再一次赋值操作
12 @show_time  # foo = show_time(foo)
13 def foo():
14     time.sleep(2)
15     print(hello foo)
16 
17 foo()

装饰器在python使用如此方便都要归因于python函数能像普通的对象一样能作为参数传递给其他函数,可以被赋值给其他变量,可以作为返回值,可以被定义在另外一个函数内。

带参数的被装饰函数

 1 import time
 2 def show_time(func):
 3     def wrapper(a,b):
 4         start_time = time.time()
 5         ret = func(a,b)
 6         stop_time = time.time()
 7         print(spend %s %(stop_time - start_time))
 8         return ret
 9 
10     return wrapper
11 
12 @show_time
13 def add1(a,b):
14     time.sleep(1)
15     print(a + b)
16 
17 add1(4,5)
18 
19 # 注意函数的返回值时
20 @show_time
21 def add2(a,b):
22     time.sleep(1)
23     return a + b
24 
25 print(add2(4,5))

不定长参数

 1 import time
 2 def show_time(func):
 3     def wrapper(*args,**kwargs):
 4         start_time = time.time()
 5         ret = func(*args,**kwargs)
 6         stop_time = time.time()
 7         print(spend %s %(stop_time - start_time))
 8         return ret
 9 
10     return wrapper
11 
12 @show_time
13 def add(*args,**kwargs):
14     time.sleep(1)
15     sum = 0
16     for i in args:
17         sum += i
18     print(sum)
19 
20 add(4,5,6,7,8,9)

带参数的装饰器

装饰器还有更大的灵活性,例如带参数的装饰器;在上面的装饰器调用中,比如@show_time,该装饰器唯一的参数就是执行业务的函数。装饰器的语法允许我们在调用时,提供其它参数,比如@auth(a)。这样就为装饰器的编写和使用提供了更大的灵活性。

 1 user,passwd = abc,abc123 # 存用户信息
 2 user_status = False # 用户登录了就把这个改成True
 3 
 4 def auth(auth_ytpe=0): # 把要执行的模块从这里传进来
 5     def wrapper(func):
 6         def inner(*args,**kwargs): #
 7             if auth_ytpe == 1:
 8                 global user_status
 9                 if user_status == False:
10                     username = input(Username:).strip()
11                     password = input(Password:).strip()
12                     if username == user and password == passwd: # 用户认证
13                         print(welcome login ......)
14                         user_status = True  # 登入成功改成True
15                     else:
16                         print(wrong username or password!)
17                 if user_status == True:
18                     return func(*args,**kwargs) # 验证通过,调用相应功能函数
19             elif auth_ytpe == 2:
20                 pass
21         return inner
22     return wrapper
23 
24 @auth(0)
25 def index():
26     print(welcome to index)
27 
28 @auth(1)
29 def home(a):
30     print(welcome to home %s%(a))
31     return home
32 
33 @auth(2)
34 def bbs():
35     print(welcome to bbs)
36 
37 index()
38 print(home(33))
39 bbs()

多层装饰器

 1 def w1(fnuc):
 2     def wrapper():
 3         return <b> + fnuc() + </b>
 4 
 5     return wrapper
 6 
 7 def w2(fnuc):
 8     def wrapper():
 9         return <i> + fnuc() + </i>
10 
11     return wrapper
12 
13 @w1
14 @w2
15 def hello():
16     return hello
17 
18 print(hello())

 

以上是关于Python基础05 - 装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象学习之八,装饰器

python基础---装饰器

1.16 Python基础知识 - 装饰器

python 基础篇 12 装饰器进阶

python基础-装饰器

python基础之装饰器