python三大器之装饰器详解

目录
  • 装饰器
  • 总结

装饰器

讲装饰器之前要先了解两个概念:

  • 对象引用 :对象名仅仅只是个绑定内存地址的变量
def func():   # 函数名仅仅只是个绑定内存地址的变量
	print("i`m running")
# 这是调用
func()  # i`m running
# 这是对象引用,引用的是内存地址
func2 = func
print(func2 is func)  # True
# 通过引用进行调用
func2()  # i`m running
  • 闭包:定义一个函数A,然后在该函数内部再定义一个函数B,并且B函数用到了外边A函数的变量

    def out_func():
    	out_a = 10
    	def inner_func(inner_x):
    		return out_a + inner_x
    	return inner_func
    
    out = out_func()
    print(out)  # <function out_func.<locals>.inner_func at 0x7ff378af5c10> out_func返回的是inner_func的内存地址
    print(out(inner_x=2))  # 12
    

装饰器和闭包不同点在于:装饰器的入参是函数对象,闭包入参是普通数据对象

def decorator_get_function_name(func):
	"""
	获取正在运行函数名
	:return:
	"""
	def wrapper(*arg):
		"""
		wrapper
		:param arg:
		:return:
		"""
		print(f"当前运行方法名:{func.__name__}  with  params: {arg}")
		return func(*arg)
	return wrapper

@decorator_get_function_name
def test_func_add(x, y):
	print(x + y)

@decorator_get_function_name
def test_func_sub(x, y):
	print(x - y)

test_func_add(1, 2)
# 当前运行方法名:test_func_add  with  params: (1, 2)
# 3
test_func_sub(3, 5)
# 当前运行方法名:test_func_sub  with  params: (3, 5)
# -2

常用于如鉴权校验,例如笔者会用于登陆校验:

def login_check(func):
    def wrapper(request, *args, **kwargs):
        if not request.session.get('login_status'):
            return HttpResponseRedirect('/api/login/')
        return func(request, *args, **kwargs)
    return wrapper
@login_check
def edit_config():
	pass

装饰器内部的执行逻辑:

"""
>  1. def login_check(func):  ==>将login_check函数加载到内存
>  ....
>  @login_check  ==>此处已经在内存中将login_check这个函数执行了!;并不需要等edit_config()实例化调用
>  2. 上例@login_check内部会执行以下操作:
>	  2.1 执行login_check函数,并将 @login_check 下面的 函数(edit_config) 作为login_check函数的参数,即:@login_check 等价于 login_check(edit_config)
>     2.2 内部就会去执行:
      def wrapper(*args):
          # 校验session...
          return func(request, *args, **kwargs)   # func是参数,此时 func 等于 edit_config,此处相当于edit_config(request, *args, **kwargs)
      return wrapper     # 返回的 wrapper,wrapper代表的是函数对象,非函数实例化对象
      2.3 其实就是将原来的 edit_config 函数塞进另外一个函数中,另一个函数当中可以做一些操作;再执行edit_config
      2.4 将执行完的 login_check 函数返回值(也就是 wrapper对象)将此返回值再重新赋值给新 edit_config,即:
      2.5 新edit_config = def wrapper:
             # 校验session...
            return 原来edit_config(request, *args, **kwargs)
>  3. 也就是新edit_config()=login_check(edit_config):wrapper(request, *args, **kwargs):return edit_config(request, *args, **kwargs) 有点绕,大家看步骤细细理解。
"""

同样一个函数也可以使用多个装饰器进行装饰,执行顺序从上到下

from functools import wraps
def w1(func):
	@wraps(func)
	def wrapper(*args, **kwargs):
		print("这里是第一个校验")
		return func(*args, **kwargs)
	return wrapper

def w2(func):
	@wraps(func)
	def wrapper(*args, **kwargs):
		print("这里是第二个校验")
		return func(*args, **kwargs)
	return wrapper

def w3(func):
	def wrapper(*args, **kwargs):
		print("这里是第三个校验")
		return func(*args, **kwargs)
	return wrapper

@w2  # 这里其实是w2(w1(f1))
@w1  # 这里是w1(f1)
def f1():
	print(f"i`m f1, at {f1}")

@w3
def f2():
	print(f"i`m f2, at {f2}")
# ====================== 实例化阶段 =====================
f1()
# 这里是第二个校验
# 这里是第一个校验
# i`m f1, at <function f1 at 0x7febc52f5e50>
f2()
# 这里是第三个校验
# i`m f2, at <function w3.<lo

有同学可能要好奇 为什么f1对象打印的是“<function f1 at 0x7febc52f5e50>”,f2对象打印的是“<function w3..wrapper at 0x7febc52f5f70>”(也就是步骤2.5造成的,赋的值是wrapper对象),这就跟w1和w2 内部wrapper使用的wraps装饰器有关系了。

wraps的作用是:被修饰的函数(也就是里面的func)的一些属性值赋值给修饰器函数(wrapper)包括元信息和“函数对象”等。

同时装饰器也可以接受参数:

def decorator_get_function_duration(enable):
	"""
	:param enable:  是否需要统计函数执行耗时
	:return:
	"""
	print("this is decorator_get_function_duration")
	def inner(func):
		print('this is inner in decorator_get_function_duration')
		@wraps(func)
		def wrapper(*args, **kwargs):
			print('this is a wrapper in decorator_get_function_duration.inner')
			if enable:
				start = time.time()
				print(f"函数执行前:{start}")
				result = func(*args, **kwargs)
				print('[%s]`s enable was %s it`s duration : %.3f s ' % (func.__name__, enable, time.time() - start))
			else:
				result = func(*args, **kwargs)
			return result
		return wrapper
	return inner

def decorator_1(func):
	print('this is decorator_1')
	@wraps(func)
	def wrapper(*args, **kwargs):
		print('this is a wrapper in decorator_1')
		return func(*args, **kwargs)
	return wrapper

def decorator_2(func):
	print('this is decorator_2')
	@wraps(func)
	def wrapper(*args, **kwargs):
		print('this is a wrapper in decorator_2')
		return func(*args, **kwargs)
	return wrapper

@decorator_1 # 此处相当:decorator_1(decorator_2(decorator_get_function_duration(enable=True)(fun)))
@decorator_2 # = decorator_2(decorator_get_function_duration(enable=True)(fun))
@decorator_get_function_duration(enable=True)  # = decorator_get_function_duration(enable=True)(fun)
def fun():
	time.sleep(2)
	print("fun 执行完了~")

fun()
# ======== enable=False ============
"""
this is decorator_get_function_duration
this is inner in decorator_get_function_duration
this is decorator_2
this is decorator_1
this is a wrapper in decorator_1
this is a wrapper in decorator_2
this is a wrapper in decorator_get_function_duration.inner
fun 执行完了~
"""
# ======== enable=True ============
"""
this is decorator_get_function_duration
this is inner in decorator_get_function_duration
this is decorator_2
this is decorator_1
this is a wrapper in decorator_1
this is a wrapper in decorator_2
this is a wrapper in decorator_get_function_duration.inner
函数执行前:1634635708.648994
fun 执行完了~
[fun]`s enable was True it`s duration : 2.002 s
"""

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 详解Python装饰器之@property

    一.property() 函数讲解 了解 @property 装饰器之前,我们首先要了解内置函数的 property(). class property(fget=None, fset=None, fdel=None, doc=None) 描述: 返回 property 属性. 参数说明: fget -- 获取属性值的函数. fset -- 设置属性值的函数. fdel -- 删除属性值函数. doc -- property 属性的文档字符串,如果没有给出 doc,则该 property 将拷贝

  • Python pytest装饰器总结(实例详解)

    几个常用装饰器 pytest.ini 配置文件 例子: [pytest] addopts = -v -s --html=py_test/scripts/report/report.html -p no:warnings --reruns=10 testpaths = ./py_test/scripts python_files= test_rerun.py python_classes = Test* python_function = test* xfail_strict = true add

  • Python 函数装饰器详解

    目录 使用场景 授权(Authorization) 日志(Logging) 带参数的装饰器 在函数中嵌入装饰器 装饰器类 总结 装饰器(Decorators)是 Python 的一个重要部分.简单地说:他们是修改其他函数的功能的函数.他们有助于让我们的代码更简短,也更Pythonic(Python范儿).大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁.首先,让我们讨论下如何写你自己的装饰器. 这可能是最难掌握的概念之一.我们会每次只讨论一个步骤,这样你能

  • Python装饰器代码详解

    目录 一.理解装饰器 二.装饰器原型 1.不带参数的装饰器 2.带参数的被装饰的函数 3.带参数的装饰器 4.使用类作为装饰器 5.使用对象作为装饰器 6.多层装饰器的嵌套 总结 一.理解装饰器 所有东西都是对象(函数可以当做对象传递) 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. def function_one(): print("测试函数") #可以将一个函数赋值给一个变量,比如 foo =function_one #这里没有在使用小括号,因

  • Python语法详解之decorator装饰器

    python 是一门优雅的语言,有些使用方法就像魔法一样.装饰器(decorator)就是一种化腐朽性为神奇的技巧.最近一直都在使用 Tornado 框架,一直还是念念不忘 Flask .Flask 是我最喜欢的 Python 框架,最早被它吸引也是源自它使用装饰器这个语法糖(Syntactic sugar)来做 Router,让代码看上去就感觉甜甜的. Tornado 中的 Router 略显平淡,怀念 Flask 的味道,于是很好奇的想知道 Flask 是如何使用这个魔法.通过阅读 Flas

  • python三大器之装饰器详解

    目录 装饰器 总结 装饰器 讲装饰器之前要先了解两个概念: 对象引用 :对象名仅仅只是个绑定内存地址的变量 def func(): # 函数名仅仅只是个绑定内存地址的变量 print("i`m running") # 这是调用 func() # i`m running # 这是对象引用,引用的是内存地址 func2 = func print(func2 is func) # True # 通过引用进行调用 func2() # i`m running 闭包:定义一个函数A,然后在该函数内

  • python基础之装饰器详解

    一.前言 装饰器:本质就是函数,功能是为其他函数添加附加功能 原则: 1.不修改被修饰函数的源代码 2.不修改被修饰函数的调用方式 装饰器 = 高阶函数 + 函数嵌套 + 闭包 二.高阶函数 高阶函数定义: 1.函数接收的参数是一个函数 2.函数的返回值是一个函数名 3.满足上述条件任意一个,都可以称为高阶函数 test 函数是高阶函数,接受了一个foo 作为参数 import time def foo(): time.sleep(3) print("sleep 3s") def te

  • python中的装饰器详解

    在了解装饰器的之前一定要先了解函数作为参数传递, 什么是函数内嵌,请参考我之前写的博客函数简介 因为在python里面,函数也是对象,也可以作为参数进行传递.python装饰器本质也是一种特殊函数,它接收的参数是函数对象,然后动态地函数参数添加额外的功能,而不用修改原有的函数对象.python装饰器传入的参数是函数,返回的值也是函数! python装饰器思想有点类似设计模式的装饰模式, 其意图是动态地给函数对象添加额外的功能.比如像增加日志打印的功能,有点面向切面编程(AOP)的感觉. 装饰器语

  • Python 3.7新功能之dataclass装饰器详解

    前言 Python 3.7 将于今年夏天发布,Python 3.7 中将会有许多新东西: 各种字符集的改进 对注释的推迟评估 以及对dataclass的支持 最激动人心的新功能之一是 dataclass 装饰器. 什么是 Data Class 大多数 Python 开发人员编写过很多像下面这样的类: class MyClass: def __init__(self, var_a, var_b): self.var_a = var_a self.var_b = var_b dataclass 可以

  • python高级语法之闭包和装饰器详解

    一.闭包 闭包的形成条件: 1.函数嵌套. 2.内部函数使用了外部函数的变量或者参数. 3.外部函数返回了使用外 部变量的内部函数. 二.一个简单的例子 def func_out(num1): def inner(num2): res = num1 + num2 print(res) return inner # a = func_out(10)(10) a = func_out(10) a(10) 闭包修改外部函数的变量: 在闭包内修改外部函数的变量需要使用nonlocal关键字 def fu

  • python 装饰器详解与应用范例

    什么是装饰器 从字面意思上来看,装饰器是用来装饰其他东西的工具.在python中装饰器分为函数装饰器和类装饰器. 简而言之,函数装饰器是用来装饰函数的装饰器,其主要目的是增加目标函数的功能,类装饰器也就是装饰类的装饰器,增加类的功能. 函数装饰器 装饰器本质是嵌套函数 下面是一个简单的装饰器 # fun1为装饰器名称,function指的是被装饰的函数 def fun1(function): def fun2(): print("开始了!") function() # 执行被装饰的函数

  • python中的迭代器,生成器与装饰器详解

    目录 迭代器 生成器 装饰器 总结 迭代器 每一个可迭代类内部都要实现__iter__()方法,返回一个迭代类对象,迭代类对象则定义了这个可迭代类如何迭代. for循环调用list本质上是是调用了list的迭代器进行迭代. # 对list进行for循环本质上是调用了list的迭代器 list = [1,2,3,4] # for 循环调用 for elem in list: print(elem) # 迭代器调用 list_iter = list.__iter__() while True: tr

  • Python学习之装饰器与类的装饰器详解

    目录 装饰器 装饰器的定义 装饰器的用法 类中的装饰器 类的装饰器-classmethod 类的装饰器-staticmethod 类的装饰器-property 通过学习装饰器可以让我们更好更灵活的使用函数,通过学会使用装饰器还可以让我们的代码更加优雅. 在我们的实际工作中,很多场景都会用到装饰器,比如记录一些日志.或者屏蔽一些不太合法的程序执行从而使我们的代码更加安全. 装饰器 什么是装饰器?虽然对这个次感到陌生,但是完全不需要担心. 首先,装饰器也是一种函数:只不过装饰器可以接收 函数 作为参

  • Python中的各种装饰器详解

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: 复制代码 代码如下: >>> def test(func):     def _test():         print 'Call the function %s().'%func.func_name         return func()     return _test >

随机推荐