python 装饰器 用法笔记

https://www.programiz.com/python-programming/decorator

Python 中所有的东西都是对象(objects),函数也是 objects (带有属性的 object),如:

def first(msg):
	print(msg)
first("Hello")
second = first 
second("Hello")

他们得到的输出是相同的,这里 firstsecond 指的是同一个函数对象。

函数可以作为参数传递给另一个函数。以其他函数作为参数的函数也叫做高阶函数(higher order functions),比如:

def inc(x):
	return x + 1
def dec(x):
	return x - 1
def operate(func, x):
	result = func(x) 
	return result

在这里插入图片描述
函数也可以返回另一个函数:

def is_called():
	def is_returned():
		print("Hello")
	return is_returned
new = is_called()
new() # output: Hello

假如函数和方法可以被调用(call),则称其为可调用的(callable)。实际上对于任意一个对象来讲,假如它实现了 __call__() 方法,那么它就是可以被调用的。所以在最基础的情况下,一个装饰器是一个返回可调用对象的可调用对象(a decorator is a callable that returns a callable)

基础上讲,装饰器接受一个函数作为输入,给这个函数加一些功能,然后再返回它:

def make_pretty(func):
	def inner():
		print("I got decorated")
		func()
	return inner
def ordinary():
	print("I am ordinary")

在这里插入图片描述
其中 make_pretty 是一个装饰器,在赋值的过程中:

pretty = make_pretty(ordinary)

这一句中,函数 ordinary 被装饰后返回,赋给了 pretty 。装饰器的作用像一个 wrapper,一般来讲,装饰后的函数会赋给它自己:

ordinary = make_pretty(ordinary)

这一做法很常见,因此 Python 提供了一个语法来进行简化:

@make_pretty
def ordinary():
	print("I am ordinary")

这一写法等价于:

def ordinary():
	print("I am ordinary")
ordinary = make_pretty(ordinary)

如果想在装饰过程中加入参数,该怎么做呢?比如:

def divide(a, b):
	return a/b

这个函数有两个参数:a,b,设计一个装饰器来避免除以零的错误:

def smart_divide(func):
	def inner(a,b):
		print("I am going to divide", a, "and", b)
		if b==0:
			print("Whoops! cannot divide")
			return 
		return func(a,b)
	return inner
@smart_divide
def divide(a,b):
	return a/b

此时假如除以零的话会返回 None

在这里插入图片描述
可以注意到 inner 接受的参数和要装饰的函数是一样的,因此可以设计更加一般的装饰器:

def works_for_all(func):
	def inner(*args, **kwargs):
		print("I can decorate any function")
		return func(*args, **kwarg)
	return inner

其中 function(*args, **kwargs) 里的 args 为位置参数(positional arguments),kwargs 表示一个关键词参数的字典(the dictionary of keyword arguments)

可以将多个装饰器级联起来:

def star(func):
	def inner(*args, **kwargs):
		print("*" * 30)
		func(*args, **kwargs)
		print("*" * 30)
	return inner
def percent(func):
	def inner(*args, **kwargs):
		print("%" * 30)
		func(*args, **kwargs)
		print("%" * 30)
	return inner 
@star
@percent
def printer(msg):
	print(msg)
printer("Hello")
"""output:
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Hello
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
"""

上述操作等价于:

def printer(msg):
	print(msg)
printer = star(percent(printer))

装饰的顺序对结果是有影响的,假如这样装饰:

@percent
@star
def printer(msg):
	print(msg)

结果为:

"""
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
Hello
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
"""
posted @ 2020-04-27 12:35  winechord  阅读(81)  评论(0编辑  收藏  举报