python装饰器 和单例模式

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

内嵌函数:

 1 def foo():
 2     def bar():
 3         print('bar() called')
 4     print ('foo() called')
 5     return bar
 6 
 7 >>>f = foo()
 8 foo() called
 9 >>>f()
10 bar() called

相当于:

1 def foo():
2     def bar():
3         print('bar() called')
4     print ('foo() called')
5     return bar()
6 
7 >>>foo()
8 foo() called
9 bar() called

 

装饰器:是一个实现了给现有函数添加装饰功能的函数,就是把原来的函数给包了起来,在不改变原函数代码的情况下,在外面起到了装饰作用

  1. 它的参数是需要被装饰的函数
  2. 返回值是新定义的一个包装了原有函数的函数。

在被装饰的函数前使用@符号指定装饰器,在运行程序的时候,Python解释器会根据@标注自动生成装饰器函数,并调用装饰器函数。

 

带参数的函数:

 1 import time
 2 
 3 def timer(func):
 4  '''统计函数运行时间的装饰器'''
 5  def wrapper(*args, **kwargs):
 6   start = time.time()
 7   func(*args, **kwargs)
 8   end = time.time()
 9   used = end - start
10   print(f'{func.__name__} used {used}')
11  return wrapper
  1. wrapper使用了通配符,*args代表所有的位置参数,**kwargs代表所有的关键词参数。这样就可以应对任何参数情况。
  2. wrapper调用被装饰的函数的时候,只要原封不动的把参数再传递进去就可以了。

函数返回值:

  如果被装饰的函数func有返回值,wrapper也只需把func的返回值返回就可以了。

 1 import time
 2 
 3 def timer(func):
 4  '''统计函数运行时间的装饰器'''
 5  def wrapper(*args, **kwargs):
 6   start = time.time()
 7   ret_value = func(*args, **kwargs)
 8   end = time.time()
 9   used = end - start
10   print(f'{func.__name__} used {used}')
11   return ret_value
12  return wrapper
13 
14 @timer
15 def add(num1, num2):
16  return num1 + num2
17 
18 sum = add(5, 8)
19 print(sum)

 

代码调试:

  现在我们来创建一个装饰器:它会打印函数的参数,以及返回值。

  如果你有实际项目经验,你一定会知道这个很有用。这不就是自动打印日志嘛!

 1 def debug(func):
 2     def wrapper_debug(*args, **kwargs):
 3         print(f'{func.__name__}:{args}, {kwargs}')
 4         ret_val = func(*args, **kwargs)
 5         print(f'return: {ret_val}')
 6         return ret_val
 7     return wrapper_debug
 8 
 9 @debug
10 def add(a, b):
11     return a + b
12 
13 add(1, 3)
14 add(2, 3)
15 add(4, 3)

 

装饰器模版:

1 def decorator(func):
2     def wrapper_decorator(*args, **kwargs):
3         #调用前操作
4         ret_val = func(*args, **kwargs)
5         #调用后操作
6         return ret_val
7     return wrapper_decorator

按照这个模板:

  1. 修改装饰器的名字,把decorator替换为具体的名字。
  2. 在注释“调用前操作”的地方写自己想写的代码

在注释“调用后操作”的地方写自己想写的代码。

 

posted @ 2021-08-04 15:48  小狼小狼G  阅读(202)  评论(0编辑  收藏  举报