python装饰器类型_Python各类类型装饰器详解说明

装饰器说明

Python中的装饰器是一种能够装饰其它对象的工具。

该工具本质上是一个可调用的对象(callable),因此装饰器通常能够由函数、类来实现。

装饰器自己须要接受一个被装饰的对象做为参数,该参数一般为函数、方法、类等对象。

装饰器须要返回一个对象,该对象能够是 通过处理的原参数对象、一个包装且相似原参数的对象;或者返回一个不相干内容(一般不建议使用)

相信经过上述一段文字的描述,你们应该更加的迷惑了!因此下面咱们就结合代码来理解Python中的装饰器。python

装饰器分类

最简单的装饰器

def warp(obj):

return obj

没错!!!这就是最简单的装饰器,而且是一个没有任何用处的装饰器。可是它确实是一个装饰器,而且能够用的很好。好比:bash

@warp # 等价于 foo = warp(foo)

def foo():

print('hello decorator!')

foo() # => hello decorator!

而上面使用了装饰器的代码,其实咱们能够经过其它方式达到相同的效果。具体见下:app

def foo():

print('hello decorator!')

foo = warp(foo)

foo() # => hello decorator!

So,经过最简单的代码,咱们能够发现装饰器其实就是接受了一个函数(对象),而且返回了一个函数(对象)的函数(可调用对象)。函数

用于修改对象的装饰器

在理解了装饰器的含义以后,再来看一个稍微有点做用的装饰器。代码以下:工具

def warp(obj):

obj.name = 'python'

return obj

这个装饰器在上一个例子的基础上,只添加了一行代码,可是却有了实际的做用。它的做用就是给被装饰的对象,添加一个name属性而且设置值为python。这个装饰器的使用效果以下:url

@warp # => Bar = warp(Bar)

class Bar(object):

def __init__(self):

pass

print(Bar.name) # => python

能够看到实际的使用过程当中,warp装饰器已经成功的给Bar对象添加了name属性。除了给类对象添加属性以外,它还能够给函数对象添加属性。spa

@warp # => foo = warp(foo)

def foo():

pass

print(foo.name) # => python

用于模拟对象的装饰器--函数装饰器

上面例子中的装饰器,是直接修改了传入对象;而装饰器最经常使用的方式倒是模拟一个传入对象。即返回一个和原对象类似的对象(即调用接口彻底同样的另外一个对象),而且该模拟对象是包装了原对象在内的。具体代码以下:日志

def outer(func): # 函数装饰器

def inner():

func()

return inner

上面是一个函数装饰器,即用来修饰函数的装饰器。由于它返回了一个模拟func对象的inner对象。而这里inner对象是一个函数,因此这个装饰器只能装饰函数。(由于inner对象只能模拟func这样的函数对象,不能模拟class对象)code

@outer # foo = outer(foo)

def foo():

print('hello foo')

foo() # => hello foo

上述代码中最后一行foo(),其实质上是执行的inner()。为了证实这一点,咱们能够在inner中打印一条信息。并查看下foo的__name__属性。对象

def outer(func): # 函数装饰器

def inner():

print('hello inner')

func()

return inner

@outer # foo = outer(foo)

def foo():

print('hello foo')

print(foo.__name__)

foo()

上述代码执行后的结果以下:

inner

hello inner

hello foo

能够看到首先打印的是 foo.__name__代码,注意内容是inner而不是foo(说明其本质上是inner函数);其次打印的时候,先打印inner函数中的内容,后打印foo函数中的内容。

用于模拟对象的装饰器--类方法装饰器

与函数装饰器相似的还有类方法装饰器,其做用相同,格式相近。只是些微有些区别,下面就是类方法装饰器的代码。

def outer(obj): # 类方法装饰器

def inner(self):

print('hello inner')

obj(self)

return inner

class Zoo(object):

def __init__(self):

pass

@outer # => zoo = outer(zoo)

def zoo(self):

print('hello zoo')

zoo = Zoo()

print(zoo.zoo.__name__)

zoo.zoo()

能够看到类方法装饰器和函数装饰器,惟一的区别就是多了一个默认的self参数;这是由于类方法自己就比函数多这么一个参数。其执行的结果以下:

inner

hello inner

hello zoo

因此最后一行代码zoo.zoo函数执行的实际上是inner函数。

用于模拟对象的装饰器--类装饰器

装饰器除了能够装饰函数、方法以外,还能够装饰器类对象。具体的代码以下:

def outer(clss): # 类装饰器

class Inner(object):

def __init__(self):

self.clss = clss()

def __getattr__(self, attr):

return getattr(self.clss, attr)

return Inner

@outer # Zoo = outer(Zoo)

class Zoo(object):

def __init__(self):

pass

def say(self):

print('hello world!')

zoo = Zoo()

print(zoo.__class__) # .Inner'>

zoo.say() # hello world!

经过代码能够看出,类装饰器与函数装饰器相似。即模拟一个与原参数接口一致的类对象。因此对于模拟类的装饰器,只能用在其能够模拟的对象之上,并不能互相修饰其它类型的对象。

特殊应用的装饰器

上面都是比较常规的装饰器,python中还有另一些特殊的装饰器。好比:类静态属性装饰器。好比下面的代码:

class Foo(object):

def __init__(self, height, weigth):

self.height = height

self.weigth = weigth

@property

def ratio(self):

return self.height / self.weigth

foo = Foo(176, 120)

print(foo.ratio) # => 1.4666666666666666

上述代码中的@property装饰器就是一个特殊的装饰器,它把ratio方法变成了一个属性。从最后一句调用代码能够看出,使用的是foo.ratio而不是foo.ratio()。

对于这类装饰器须要Python的特定属性和机制的支持才能够实现,不一样特性的装饰器所需机制不一样。如上述代码中的@property装饰器就可使用下面的代码来实现。

class Prop(object):

def __init__(self, fget):

self.fget = fget

def __get__(self, instance, owner):

return self.fget(instance)

具体的使用效果以下:

class Foo(object):

def __init__(self, height, weigth):

self.height = height

self.weigth = weigth

@Prop

def ratio(self):

return self.height / self.weigth

foo = Foo(176, 120)

print(foo.ratio) # => 1.4666666666666666

能够看到效果和原生的@property装饰器是同样的。

类实现的装饰器

在以前对于装饰器的说明中,有说道装饰器是一个callable对象。除了函数能够实现装饰器以外,还能够经过类来实现。那么类实现装饰器的具体代码以下:

class Warp(object):

def __init__(self):

pass

def __call__(self, obj):

obj.name = 'warp'

return obj

这个类装饰器实现的功能,也是给传入的对象添加name属性,并设置其值为warp。其调用效果以下:

@Warp()

def foo():

pass

print(foo.name) # => warp

装饰带参数/返回值的对象

前面列举的全部例子,被装饰的对象都是无参数的。若是你须要装饰一个带参数的对象。那么就须要响应的修改下装饰器代码了。注意:这里特指那些模拟类型的装饰器。即函数装饰器、类方法装饰器、类装饰器。

假设咱们先有一个带参数的函数,其内容以下:

def add(x, y):

return x * y

若是使用原来的函数装饰器,确定就会出错。主要由于这个函数带参数,而且也有返回值。而原来的函数装饰器则不能支持,原函数装饰器以下:

def outer(func): # 函数装饰器

def inner():

func()

return inner

能够看到inner模拟的仅仅是一个无参数、无返回值的对象。因此须要进行以下的修改:

def outer(func): # 函数装饰器

def inner(x, y):

print('hello inner')

return func(x, y)

return inner

这样的函数装饰器就能够装饰add函数了。由于inner函数添加了x,y参数,调用func对象时也添加了参数,而且返回了func对象的返回值。具体使用效果以下:

@outer

def add(x, y):

return x * y

print(add(2, 3)) # => 6

上述代码虽然能够实现add的装饰功能,可是若是如今咱们在出现一个三个参数的函数须要装饰,或者一个带默认值参数的韩式须要装饰怎么办。咱们不可能为没一个不一样参数的函数都写一个相同功能的装饰器。因此终极的函数装饰器的写法以下:

def outer(func): # 函数装饰器

def inner(*args, **kwargs):

print('hello inner')

return func(*args, **kwargs)

return inner

这里使用了python中动态参数的概念,这样装饰器就能够支持任意的组合参数的函数了。

装饰器带参数

上面说到的是被修饰的对象带参数的状况,还有一种状况就是装饰器自己但愿支持带参数。这种状况相似于函数模块经过带参数能够更加灵活的道理同样。经过给装饰器带上参数,可使得装饰器的功能更加的灵活。代码以下:

url_mapping = {}

def route(url):

def decorator(func): # 函数装饰器

url_mapping[url] = func

return func

return decorator

上面是一个URL路由映射的装饰器,能够给不一样的函数绑定不一样的路由。若是装饰器不能带参数,则没法实现这样的功能。其使用效果以下:

@route('/home')

def home():

pass

@route('/index')

def index():

pass

print(url_mapping) # => {'/home': , '/index': }

装饰器应用

Python装饰器的应用比较普遍,大部分场景的公共处理逻辑均可以使用装饰器去简化。(使用上相似于JAVA中的注解)通常比较常见的场景好比:

日志记录

权限验证

单例模式

竞争资源管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值