python深入学习--decorator强大的装饰器

一.decorator基础。

最初接触python是在大学毕业进入某一游戏公司后,最开始觉得python不严谨,很不喜欢python这种“简单”的脚本,但是后来,越来越离不开python了,觉得这么灵活方便的语言,简直是程序员的福音,尤其是它的数据结构,他带来了一个“{}” 大括号就能搞定一切的时代。当然python还有很多优秀的特性。现在我们来讲python的特性之一--decorator(装饰器)。

装饰器,顾名思义就是修饰函数或者类的,它把要装饰的函数作为参数,然后在函数体内可以执行很多灵活的操作。这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。跟着装饰器声明的是被修饰的函数,和装饰函数的可选参数。装饰器看起来会是这样:

@decorator()
def func(*args):
	pass

func(*args)

其解释器会解释成下面这样的语句:

func = decorator(func)
func(*args)

其实,写过python的人都接触过@decorator。比如写一个单例类:

class Singleton(object):
	_instance = None
	def __init__(self):
		print "init single"

	@classmethod
	def instance(cls):
		if cls._instance is None:
			cls._instance = Singleton()
		return cls._instance

	def func(self):
		print "call func"

@classmethod就是一个decorator,是python内置的装饰器(还有@staticmethod...)

class Singleton(object):
	_instance = None
	def __init__(self):
		print "init single"

	#@classmethod
	def instance(cls):
		if cls._instance is None:
			cls._instance = Singleton()
		return cls._instance

	instance = classmethod(instance)

	def func(self):
		print "call func"

Singleton.instance().func()

以上跟这个效果是一样的。只不过却让instance少写了两次。

二.decorator的用法。

1.修饰函数:

decorator修饰函数有几种用法。

1).单个Decorator,不带参数

def deco(func):
	def call_method(*args):
		print "before call method"
		func(*args)
		print "after call method"
	return call_method

@deco()
def func(a,b):
	print "in func"
	return a + b

func(1,2)

输出为:

before call method

in func

after call method

以上对于func的调用 跟以下是一样的(注释掉@deco()):

func = deco(func)
func(1,2)

再写的明白点:

call_method = deco(func)  #deco这个函数返回call_method

call_method(*args)  # 是不是恍然大悟了。

当然,最初的写法是最简单的,它让你每一个调用func()的地方都自动调用了@deco(),然后执行一些额外的操作。比如  print "after call method".当然你可以做你想做的任何事,比如在这里记log,你就不需要边CTRL+C,CTRL+V在每一个调用func的地方加上相同的代码了。

2).单个decorator,带参数。

def deco(a):
	def real_deco(func):
		def call_method(*args):
			print "before call method"
			result = a + func(*args)
			print "after call method ",result
		return call_method
	return real_deco

@deco("Hello ")
def func(name):
	print "in func ",name
	return name

func("World!")
func("No World!")

输出为:

before call method

in func  World!

after call method  Hello World!

before call method

in func  No World!

after call method  Hello No World!

总结:

无参数decorator:把函数名传进去,然后生成一个新的装饰器函数

有参decorator:有参装饰,装饰函数先处理参数,再生成一个新的装饰器函数,然后对函数进行装饰

3).decorator还可以有多个,如下图所示:

@dec_a
@dec_b
@dec_c
def method(args):
    pass
print "=========="
method = dec_a(dec_b(dec_c(method)))

只不过,平时项目中极少用到,我也就不讲了。

那么什么是装饰器?

现在我们知道装饰器实际就是函数。我们也知道他们接受函数对象。但它们是怎样处理那些函数的呢?一般说来,当你包装一个函数的时候,你最终会调用它。最棒的是我们能在包装的环境下在合适的时机调用它。我们在执行函数之前,可以运行些预备代码,也可以在执行代码之后做些清理工作。所以当你看见一个装饰器函数的时候,很可能在里面找到这样一些代码,它定义了某个函数并在定义内的某处嵌入了对目标函数的调用或者至少一些引用。从本质上看,这些特征引入了java 开发者称呼之为AOP(Aspect Oriented Programming,面向方面编程)的概念。

你可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:

引入日志

增加计时逻辑来检测性能

给函数加入事务的能力

2.修饰类:

修饰类和修饰函数差不多,修饰类是把@decorator放在class上面,用以修改类的属性

<span style="font-size:14px;">def func(self):
	return "func"

def deco(kclass):
	kclass.func = func
	kclass.name = "Hello"
	return kclass

@deco
class test(object):
	def __init__(self):
		print "in init",self.name
		print "call func: ",self.func()

test()</span>

输出:

in init Hello

call func:  func

三.项目实践

1.最近项目中用到decorator比较多。其中有修饰类的:

<span style="font-size:14px;">def is_persistent(_self):
	return True

def Persistent(klass):
	"""
	类的decorator,用来修饰Entity的子类。如:
	@Persistent
	class player(Entity):
		...
	这样的类才会被序列化到mongodb中
	"""
	klass.is_persistent = is_persistent
	return klass

@Persistent
class player(Entity):
	pass</span>

相当于在 player里面定义了一个 is_persistent()的方法。在需要Persistent的地方加上@Persistent就行了,当然也可以在每个需要@Persistent的类里面重写这个方法,但是当对象多的时候,自己也不知道自己写了没有了。

2.用在callback里面,但是callback的参数有的存在,有的还需要经过复杂的操作获取,假如你要经过一个异步的操作,操作回来调用func(requestId,*args),requestId是已知的,但是*args是回调回来才有的,你肯定有地方可以存requestId,然后回调回来,再取值进行func操作,但是使用类似decorator的操作可以简化这一操作:

<span style="font-size:14px;">def request_decorator(requestId, func):
	"""
	传递请求序号参数,用于回调
	:param func:
	:return:
	"""
	def requestId_callback(*args):
		return func(requestId, *args)
	return requestId_callback

callback = request_decorator(requestId, self.call_func)
...
args = ...
callback(*args)</span>

巧妙的把已有的参数传进去,然后等其他参数回来就可以了。

时间: 2024-08-24 20:42:41

python深入学习--decorator强大的装饰器的相关文章

Python学习之三大名器-装饰器、迭代器、生成器

Python学习之三大名器-装饰器.迭代器.生成器 一.装饰器     装饰,顾名思义就是在原来的基础上进行美化及完善,器这里指函数,所以说装饰器就是装饰函数,也就是在不改变原来函数的代码及调用方式的前提下对原函数进行功能上的完善.其核心原理其实是利用闭包.     格式 @关键字+装饰函数          被装饰函数()      注意:@行必须顶头写而且是在被装饰函数的正上方     按照形式可以分为:无参装饰器和有参装饰器,有参装饰器即给装饰器加上参数     以下示例是一个无参装饰器,

python中的函数式编程与装饰器

2.1 python中的函数式编程 函数式编码的特点 把计算视为函数而非指令 纯函数式编程,不需要变量,没有副作用,测试简单 支持高阶函数,代码简洁 python支持的函数式编程 不是纯函数式编码:允许有变量 支持高阶函数:函数也可以作为变量传入 支持闭包:有了闭包就能返回函数 有限度地支持匿名函数 2.2 python中高阶函数 函数名可以作为变量,如 高阶函数:只能接收函数作为参数的函数 变量可以是指向函数 函数的参数可以接收变量 一个函数可以接收另一个函数作为参数 能接收函数作为参数的函数

Python之面向对象:闭包和装饰器

一.闭包 1. 如果一个函数定义在另一个函数的作用域内,并且引用了外层函数的变量,则该函数称为闭包. def outter(): name='python' def inner(): print name return inner res=outter() 把inner的地址赋值给res res() 相当于执行inner()函数.通过闭包,可以把局部变量在外部也可以使用 2.判断是否为闭包 res.func_closure inner()函数就是一个闭包 3.通过闭包,可以把局部变量在外部也可以

Python之命名空间、闭包、装饰器

一.命名空间 1. 命名空间 命名空间是一个字典,key是变量名(包括函数.模块.变量等),value是变量的值. 2. 命名空间的种类和查找顺序 - 局部命名空间:当前函数 - 全局命名空间:当前模块 - 内建命名空间:所有Python环境,所有模块 查找顺序 1.先在当前 (嵌套的或 lambda) 函数的命名空间中搜索 2.然后是在父函数的命名空间中搜索 3.接着是模块命名空间中搜索 4.最后在内置命名空间中搜索 要到内置命名空间都没找到的话,就会弹出NameError 这里看一个例子 i

Python小程序练习二之装饰器小例子

Python小程序练习二之装饰器小例子 装饰器: 装饰器实际上就是为了给某程序增添功能,但该程序已经上线或已经被使用,那么就不能大批量的修改源代码,这样是不科学的也是不现实的,因为就产生了装饰器,使得其满足: 1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 那么根据需求,同时满足了这两点原则,这才是我们的目的. 装饰器的原则组成: < 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器 > 错误例子: 1.1Decorators.py 1 # The aut

python学习笔记7:装饰器

一.什么是装饰器 装饰器,它本身是一个函数. 装饰器的作用在于,在不改变现有函数的调用方式的前提下,给其新增一些功能:这些功能一般都是公用的. 它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓存.权限校验等场景.(此句引用:https://zhuanlan.zhihu.com/p/25648515) 二.学装饰器的前提知识 1.函数即变量 2.高阶函数 3.函数嵌套 以上三个知识点,在我的上一篇博客'python学习笔记6:函数'里 有详细介绍,这里不赘述 三.一个例子 1.场

python 学习笔记7(装饰器)

闭包(closure)是函数式编程的重要的语法结构. 定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). def outer(): x = 1 def inner(): print(x) return inner f = outer() f() inner就是内部函数,inner里引用了外部作用域的变量x(x在外部作用域outer里面,不是全局作用域),则这个内部函数inner就是一个闭包. 闭包=函数块+定义函数时的环

python学习进度14(装饰器)

由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25') ... >>> f = now >>> f() 2015-3-25 函数对象有一个__name__属性,可以拿到函数的名字: >>> now.__name__ 'now' >>> f.__name__ 'now' 现在,假设我们要增强now()函数的功能,比如

Python学习之路7?装饰器

一:命名空间与作用域 1.1命名空间 局部命名空间: def foo(): x=1 def func(): pass 全局命名空间: import time class ClassName:pass def foo():pass 内键命名空间: sum,max,min 等 python加载三个命名空间的顺序: 1.内键命名空间 2.全局命名空间:文件级别的或叫做模块级别的 3.局部命名空间:只有调用函数的时候才会加载,函数调用结束就被释放掉 1.2作用域 全局作用域: 1 同时x=1为全局变量