函数 -> 装饰器

  函数的4个核心概念

  1.函数可以赋与变量

def func(message):
print('Got a message: {}'.format(message)) send_message = func
send_message('hello world')
#输出
#Got a message: hello world

  2.函数可以当作函数的参数

def get_message(message):
return 'Got a message: ' + message def root_call(func, message):
print(func(message)) root_call(get_message, 'hello world')
输出
#Got a message: hello world

  3.函数里嵌套函数

def func(message):
def get_message(message):
print('Got a message: {}'.format(message))
return get_message(message) func('hello world')
输出
#Got a message: hello world

  4.函数作为函数返回值(闭包)

def func_closure():
def get_message(message):
print('Got a message: {}'.format(message))
return get_message send_message = func_closure()
send_message('hello world')
#输出
#Got a message: hello world
 

简单装饰器

  例

def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper def greet():
print('hello world') greet = my_decorator(greet)
greet()

  使用语法糖 @

def my_decorator(func):
def wrapper():
print('wrapper of decorator')
func()
return wrapper @my_decorator
def greet():
print('hello world') greet()
# 输出
# wrapper of decorator
# hello world

带有参数的装饰器

  直接在 wrapper函数中加上参数
def my_decorator(func):
def wrapper(message):
print('wrapper of decorator')
func(message)
return wrapper @my_decorator #相当于 greet == wrapper(message)
def greet(message):
print(message) greet('hello world')
# 输出
#wrapper of decorator
#hello world

  这个装饰器只能用在有一个参数的函数,如果想对任意参数的函数通用,可以这么写

def my_decorator(func):
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper

带自定义参数的装饰器

  利用装饰器自定义参数这特性,实现重复执行装饰器内部函数
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator @repeat(4)
def greet(message):
print(message) greet('hello world') # 输出:
# wrapper of decorator
# hello world
# wrapper of decorator
# hello world
# wrapper of decorator
# hello world
# wrapper of decorator
# hello world

原函数还是原函数?

greet.__name__
#输出
'wrapper' help(greet)
# 输出
Help on function wrapper in module __main__: wrapper(*args, **kwargs)

  可以看出,原函数的原信息会被wrapper取代

  如果不想其改变,那么可用内置装饰器@functools.wraps将原函数的元信息拷贝过去。
import functools

def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper @my_decorator
def greet(message):
print(message) greet.__name__ # 输出
#'greet'

类装饰器

  类装饰器主要依赖于 __call__()函数,每当调用类实例时,__call__()函数会被执行一次
class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0 def __call__(self, *args, **kwargs):
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs) @Count
def example():
print("hello world") example() # 输出
# num of calls is: 1
# hello world example() # 输出
# num of calls is: 2
# hello world

装饰器的嵌套

@decorator1
@decorator2
@decorator3
def func():
...
#相当于 decorator1(decorator2(decorator3(func)))
import functools

def my_decorator1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator1')
func(*args, **kwargs)
return wrapper def my_decorator2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('execute decorator2')
func(*args, **kwargs)
return wrapper @my_decorator1
@my_decorator2
def greet(message):
print(message) greet('hello world') # 输出
# execute decorator1
# execute decorator2
# hello world

装饰器的实例用法

  1)身份验证,不登录不允许操作

import functools

def authenticate(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
request = args[0]
if check_user_logged_in(request): # 如果用户处于登录状态
return func(*args, **kwargs) # 执行函数 post_comment()
else:
raise Exception('Authentication failed')
return wrapper @authenticate
def post_comment(request, ...)
...

  2)日志记录 可测试函数的执行时间

import time
import functools def log_execution_time(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
res = func(*args, **kwargs)
end = time.perf_counter()
print('{} took {} ms'.format(func.__name__, (end - start) * 1000))
return res
return wrapper @log_execution_time
def calculate_similarity(items):
...

  3) 合法性检测

import functools

def validation_check(input):
@functools.wraps(func)
def wrapper(*args, **kwargs):
... # 检查输入是否合法 @validation_check
def neural_network_training(param1, param2, ...):
... LRU cache. @lru_cache缓存装饰器
@lru_cache
def check(param1, param2, ...) # 检查用户设备类型,版本号等等
...

  4) try...excaption

class ServerDebugHelper:
@classmethod
def debug(cls):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
import traceback
print(traceback.format_exc())
return wrapper
return decorator

  

参考

  极客时间《Python核心技术与实战》专栏

Python进阶: Decorator 装饰器你太美的更多相关文章

  1. python进阶04 装饰器、描述器、常用内置装饰器

    python进阶04 装饰器.描述器.常用内置装饰器 一.装饰器 作用:能够给现有的函数增加功能 如何给一个现有的函数增加执行计数的功能 首先用类来添加新功能 def fun(): #首先我们定义一个 ...

  2. Python进阶(六)----装饰器

    Python进阶(六)----装饰器 一丶开放封闭原则 开放原则: ​ 增加一些额外的新功能 封闭原则: ​ 不改变源码.以及调用方式 二丶初识装饰器 装饰器: ​ 也可称装饰器函数,诠释开放封闭原则 ...

  3. Python进阶之装饰器

    函数也是对象 要理解Python装饰器,首先要明白在Python中,函数也是一种对象,因此可以把定义函数时的函数名看作是函数对象的一个引用.既然是引用,因此可以将函数赋值给一个变量,也可以把函数作为一 ...

  4. 项目解析1、登录验证用户是否存在 储备知识 Python 之 decorator装饰器

    下面是我对 装饰器 这一小节的总结, 以及自己的理解. 注:[本文中的代码参考上述教程] 很多时候我会把Python的很多语法与C++相融合,在C++中,函数的名称即为函数的地址,我们可以通过定义成为 ...

  5. python进阶(三)~~~装饰器和闭包

    一.闭包 满足条件: 1. 函数内嵌套一个函数: 2.外层函数的返回值是内层函数的函数名: 3.内层嵌套函数对外部作用域有一个非全局变量的引用: def func(): print("=== ...

  6. [Python进阶]002.装饰器(1)

    装饰器(1) 介绍 HelloWorld 需求 使用函数式编程 加入装饰器 解析 介绍 Python的装饰器叫Decorator,就是对一个模块做装饰. 作用: 为已存在的对象添加额外功能. 与Jav ...

  7. Python进阶(装饰器)

    from datetime import datetime def log(func):#func表示装饰器作用于的函数 def wrapper(*args,**kw):#wrapper返回装饰器作用 ...

  8. python进阶:装饰器

    1.闭包 简单理解:闭包就是多层函数的嵌套,外层函数的返回值是内层函数的引用. def out_func(n): num = 100 def in_fucn(*args,**kwargs): # no ...

  9. Python进阶之decorator装饰器

    decorator装饰器 .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB&quo ...

随机推荐

  1. 从零开始带你成为JVM实战高手

    专栏大纲 1.核心gc 内存回收以及提前设置内存大小.

  2. Git的使用(1) —— 版本库

    1. 简介 Git作为一个分布式版本控制系统,其优点是不需要一直连接远端版本库就可以使用. 故其为实现分布版本控制专门设计了一整套的存储区间和语句,用来实现. (1) 本地版本库:建立在本机磁盘上的文 ...

  3. 【软工实践】Alpha冲刺(3/6)

    链接部分 队名:女生都队 组长博客: 博客链接 作业博客:博客链接 小组内容 恩泽(组长) 过去两天完成了哪些任务 描述 对推送模块进行详细划分 基于用户的协同过滤,寻找更感兴趣的话题 学习API文档 ...

  4. BDD本质及与ATDD区别

    说起BDD,你会想到什么?   在刚接触BDD(Behavior Driven Development,行为驱动开发)的时候,我以为就是用Cucumber这样的工具来编写场景用例,从而实现自动化测试, ...

  5. Java垃圾回收(java GC)

    一.GC的阶段 对每个对象而言,垃圾回收分为两个阶段:finalization和reclamation. finalization: 指运行这个对象的finalize的方法. reclamation: ...

  6. useReducer代替Redux小案例-1(七)

    使用useContext和useReducer是可以实现类似Redux的效果,并且一些简单的个人项目,完全可以用下面的方案代替Redux,这种做法要比Redux简单一些.因为useContext和us ...

  7. ueditor百度编辑器上传图片出现后端未配置好,不能正常加载插件

  8. Numpy中ndim、shape、dtype、astype的用法

    本文链接:https://blog.csdn.net/Da_wan/article/details/80518725本文介绍numpy数组中这四个方法的区别ndim.shape.dtype.astyp ...

  9. 人脸替换(FaceSwap)的一些思考

    本文链接:https://blog.csdn.net/cy1070779077/article/details/85224347人脸替换(FaceSwap)的一些思考 最一开始,我使用了openCV( ...

  10. Tosca 一不小心,我把那一排模块全关闭了,怎么打开

    #写在前面, 之前用的时候,学了很多,基本都忘记了,现在再重新用,啥啥都不记得了,我还是应该事无巨细的全部记下来 红线这一排我关了好多,在哪儿打开 在这打开