您的位置:时时app平台注册网站 > 编程知识 > Python装饰器(decorator)定义与用法精解

Python装饰器(decorator)定义与用法精解

2019-11-08 01:35

由此可以见到,装饰器会对原函数的元音信实行改换,能够行使wraps,实行原函数音讯的足够

 

你大概感兴趣的作品:

  • python怎么着定义带参数的装饰器
  • 介绍Python的@property装饰器的用法
  • Python中的各个装饰器精解
  • 深远领会python中的闭包和装饰器
  • Python装饰器的函数式编制程序详细明白
  • 详细明白Python中的装饰器、闭包和functools的教程
  • 巧用Python装饰器 免去调用父类构造函数的难为
  • Python中的多种装饰器
  • python重试装饰器示例
  • 实例批注Python编制程序中@property装饰器的用法
  • Python自定义装饰器原理与用法实例剖析

带参数的装饰器(装饰函数),

类装饰器

但是今后又有新的急需,总结求和操作耗费时间,很简短,求和前拿到一下时刻,求和后再得到壹次,求差就可以

1 @property
2 def width(self):
3 return self.__width
4 
5 @width.setter
6 def width(self, newWidth):
7 self.__width = newWidth

装饰器有2个特征,一是足以把被点缀的函数替换来其余函数, 二是足以在加载模块时候立时履行

import datetime
def calc_spend_time(func):
 def new_func(a, b):
  start_time = datetime.datetime.now()
  result = func(a, b)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
def calc_add(a, b):
 return a   b
calc_add = calc_spend_time(calc_add)
calc_add(1, 2)
wrapper
doo
def decorate(func):
    def decorate_inner(*args, **kwargs):
        print(type(args), type(kwargs))
        print('args', args, 'kwargs', kwargs)
        return func(*args, **kwargs)
    return decorate_inner

@decorate
def func_1(*args, **kwargs):
    print(args, kwargs)

if __name__ == '__main__':
    func_1('1', '2', '3', para_1='1', para_2='2', para_3='3')

#返回结果
#<class 'tuple'> <class 'dict'>
# args ('1', '2', '3') kwargs {'para_1': '1', 'para_2': '2', 'para_3': '3'}
# ('1', '2', '3') {'para_1': '1', 'para_2': '2', 'para_3': '3'}

staticmethod:把类中的方法定义为静态方法,使用staticmethod装饰的方法能够使用类可能类的实例对象来调用,无需传入self

下边写二个特别简洁明了的闭包的事例:

import time
#不定长
def show_time(f):
    def inner(*x,**y):
        start = time.time()
        f(*x,**y)
        end = time.time()
        print('spend %s'%(end - start))
    return inner

@show_time
def add(*a,**b):
    sum=0
    for i in a:
        sum =i
    print(sum)
    time.sleep(1)

add(1,2,3,4)

Python内置装饰器

 1 import time
 2 def showtime(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 def foo():
12     print('foo..')
13     time.sleep(3)
14 
15 foo = showtime(foo)
16 foo()

bar()、bar2()也可以有像样的须求,如何做?再在bar函数里调用时间函数?那样就招致大批量相似的代码,为了削减脂复写代码,大家得以这么做,重新定义三个函数:特地设准时间:

装饰器

略知生龙活虎二装饰器的前提:1.具备东西都是指标(函数能够看成对象传递) 2.闭包

@符号是装饰器的语法糖,在概念函数的时候利用,幸免再二回赋值操作

最简便易行的函数,重返三个数的和

 1 import time
 2 from functools import wraps
 3 def showtime(func):
 4 
 5     @wraps(func)    
 6     def wrapper():
 7         start_time = time.time()
 8         func()
 9         end_time = time.time()
10         print('spend is {}'.format(end_time - start_time))
11 
12     return wrapper
13 
14 @showtime  #foo = showtime(foo)
15 def foo():
16     print('foo..')
17     time.sleep(3)
18 
19 def doo():
20     print('doo..')
21     time.sleep(2)
22 
23 print(foo.__name__)
24 print(doo.__name__)

叠放装饰器

咱俩知道,在Python中等学园函授数也是被视为对象的,能够当做参数字传送递,那么只要把总结耗费时间的独自为贰个独自的函数calc_spend_time(),然后把要求总括耗费时间的函数比方calc_add的援用传递给它,在calc_spend_time中调用calc_add,那样具有的急需计算耗费时间的函数都毫无改良自身的代码了.

 

函数show_time正是装饰器,它把真正的事务方法f包裹在函数里面,看起来像foo被上下时间函数装饰了。在此个例子中,函数步向和抽离时 ,被喻为一个横断面(Aspect),这种编制程序方式被叫做面向切面包车型地铁编制程序(Aspect-Oriented Programming)。

@calc_spend_time就是语法糖,它的原形正是:calc_add = calc_spend_time(calc_add)

结果为:

装饰器本质上是二个函数,该函数用来拍卖别的函数,它能够让任何函数在无需改进代码的前提下扩展额外的成效,装饰器的重临值也是八个函数对象。它常常用来有切面供给的风貌,举个例子:插入日志、质量测量检验、事务管理、缓存、权限校验等接受场景。装饰器是鸡犬不留那类问题的绝佳设计,有了装饰器,我们就能够分离出大方与函数效用自己非亲非故的均等代码并持续起用。总结的讲,装饰器的效果与利益正是为曾经存在的指标加多额外的意义。

def calc_add(a, b):
 return a   b
calc_add(1, 2)
 1 import time
 2 class Foo(object):
 3     def __init__(self, func):
 4         self._func = func
 5 
 6     def __call__(self):
 7         start_time = time.time()
 8         self._func()
 9         end_time = time.time()
10         print('spend is {}'.format(end_time - start_time))
11 
12 @Foo  #bar = Foo(bar)
13 def bar():
14     print('bar..')
15     time.sleep(2)
16 
17 bar()

 

现在呢,函数calc_diff(a, b),计算a-b,也想总括减法操作的时间差,很好办,把这段代码复制过去.不过意气风发旦大家今后想编的是四个数学函数库,各个函数都想计算其奉行耗费时间,总不能够几个三个复制代码,想个越来越好的办法.

下直面装饰器第第多个破绽举行深入分析,

foo...
spend 1.0005607604980469
bar...

简易来说,能够把装饰器明白为贰个打包函数的函数,它通常将盛传的函数恐怕是类做一定的管理,再次回到纠正现在的对象.所以,我们能够在不改造原函数的根底上,在实践原函数前后试行别的代码.比较常用的气象有日记插入,事务管理等.

本章结构:

@time_logger(flag=1) 做了两件事:

本文实例陈诉了Python装饰器(decorator)定义与用法。分享给大家供我们参照他事他说加以考察,具体如下:

不带参数的装饰器:(装饰器,被点缀函数都不带参数)

 

def calc_spend_time(func, *args, **kargs):
 start_time = datetime.datetime.now()
 result = func(*args, **kargs)
 end_tiem = datetime.datetime.now()
 print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
def calc_add(a, b):
 return a   b
calc_spend_time(calc_add, 1, 1)
# calc_spend_time(calc_add, a=1, b=2)

实际上是对原始装饰器的二个函数的包装,并赶回一个装饰器(一个饱含参数的闭包函数),
当使用@time_logger(3)调用的时候,Python能觉察那生龙活虎层封装,并将参数字传送递到装饰器的条件去

上面的time_logger是同意带参数的装饰器。它实际是对原来装饰器的一个函数封装,并赶回一个装饰器(二个满含参数的闭包函数)。当自身们使用@time_logger(1)调用的时候,Python能够发掘那大器晚成层的卷入,并把参数字传送递到装饰器的条件中。

出口同上例

foo
doo

 

输出:

4.

实行顺序是哪些

I say hello
I say hi

 

设若二个函数被多少个装饰器修饰,其实应该是该函数先被最里面包车型大巴装饰器修饰后(上边例子中等高校函授数main()先被inner装饰,变成新的函数卡塔尔,变成另一个函数后,再次棉被服装饰器修饰

class Human(object):
 """docstring for Human"""
 def __init__(self):
  super(Human, self).__init__()
  self.message = '111'
 def say(message):
  if not message:
   message = 'hello'
  print 'I say %s' % message
 @classmethod
 def speak(cls, message):
  if not message:
   message = 'hello'
  cls.say(message)
human = Human()
human.speak('hi')

5.本文仿效

出口结果:

无参数的函数装饰器

 

    (2)@show_time   :add=show_time(add)

import datetime
def calc_spend_time(author):
 def first_deco(func):
  def new_func(*args, **kargs):
   start_time = datetime.datetime.now()
   result = func(*args, **kargs)
   end_tiem = datetime.datetime.now()
   print author, "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
  return new_func
 return first_deco
@calc_spend_time('author_1')
def calc_add(a, b):
 return a   b
@calc_spend_time('author_2')
def calc_diff(a, b):
 return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)

闭包的定义:
1卡塔尔函数嵌套
2卡塔 尔(阿拉伯语:قطر‎内部函数使用外界函数的变量
3卡塔 尔(英语:State of Qatar)外界函数的重回值为在那之中等学园函授数

不定长

注:

2.**property*:经过property装饰过的函数 不再是三个函数,而是八个property,附近完成get,set方法***

def show_time(f):
    def inner():
        start = time.time()
        f()
        end = time.time()
        print('spend %s'%(end - start))
    return inner

@show_time #foo=show_time(f)
def foo():
    print('foo...')
    time.sleep(1)
foo()

def bar():
    print('bar...')
    time.sleep(2)
bar()

Python内置的装饰器有四个:staticmethodclassmethodproperty

3.

import time
#遵守开放封闭原则
def foo():
    start = time.time()
    # print(start)  # 1504698634.0291758从1970年1月1号到现在的秒数,那年Unix诞生
    time.sleep(3)
    end = time.time()
    print('spend %s'%(end - start))
foo()
import datetime
def calc_spend_time(func):
 def new_func(a, b):
  start_time = datetime.datetime.now()
  result = func(a, b)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
@calc_spend_time
def calc_add(a, b):
 return a   b
calc_add(1, 2)

运用装饰器的后天不良:

import time
def show_time(func):
    start_time=time.time()
    func()
    end_time=time.time()
    print('spend %s'%(end_time-start_time))


def foo():
    print('hello foo')
    time.sleep(3)

show_time(foo)

classmethod:把类中的方法定义为类情势,使用classmethod装饰的不二诀要能够使用类恐怕类的实例对象来调用,并将该class对象隐式的当作第一个参数传入

3.装饰器的劣点

在上边包车型大巴装饰器调用中,比方@show_time,该装饰器唯意气风发的参数正是进行专门的工作的函数。装饰器的语法允许我们在调用时,提供别的参数,譬如@decorator(a)。那样,就为装饰器的编写制定和行使提供了更加大的油滑。

什么是装饰器(decorator)

2.

    (1)time_logger(1):获得闭包函数show_time,里面保存情况变量flag

越多关于Python相关内容可查阅本站专题:《Python数据结构与算法教程》、《Python Socket编制程序技艺总计》、《Python函数使用技术总计》、《Python字符串操作技能汇总》及《Python入门与进级精粹教程》

常用的放手装饰器:1.staticmethod: 相符达成了静态方法 注入现在,能够直接 : 类名.方法

def outer(func):
    print('enter outer', func)
    def wrapper():
        print('running outer')
        func()
    return wrapper

def inner(func):
    print('enter inner', func)
    def wrapper():
        print('running inner')
        func()
    return wrapper

@outer
@inner
def main():
    print('running main')

if __name__ == '__main__':
    main()

#返回结果
# enter inner <function main at 0x000001A9F2BCDF28>
# enter outer <function inner.<locals>.wrapper at 0x000001A9F2BD5048>
# running outer
# running inner
# running main
class Human(object):
 """docstring for Human"""
 def __init__(self):
  super(Human, self).__init__()
 @staticmethod
 def say(message):
  if not message:
   message = 'hello'
  print 'I say %s' % message
 def speak(self, message):
  self.say(message)
Human.say(None)
human = Human()
human.speak('hi')

装饰器的原型:

严俊来讲,装饰器只是语法糖,装饰器是可调用的对象,能够像符合规律的可调用对象那样调用,特殊的地点是装饰器的参数是二个函数

property:把措施成为属性

3.classmethod: 与staticmethod很雷同,貌似就唯有那一点分别:
率先个参数需就算意味着自己类的 cls 参数,
能够来调用类的品质,类的措施,实例化对象等。

然而那样的话,你根底平台的函数改善了名字,轻易被业务线的人投诉的,因为大家每趟都要将贰个函数作为参数字传送递给show_time函数。何况这种措施已经毁损了庐山面目目标代码逻辑结构,此前实行工作逻辑时,奉行运营foo(),可是今后只可以改成show_time(foo)。那么有未有越来越好的点子的呢?当然有,答案就是装饰器。

看起来也不易,担任总计的函数不用改过,只需调用的时候作为参数字传送给总括时间差的函数.但正是那,调用的时候情势变了,不再是clac(1, 2),而是calc_spend_time(clac_add, 1, 2),万一calc_add大面积被调用,那么还得风度翩翩处生龙活虎处找,然后改正回复,还是很麻烦.如若想不更动代码,就得使clac()calc_spend_time(clac)效果与利益相符,那么能够在calc_spend_time()里把传播的clac包装一下,然后回来包装后的新的函数,再把再次来到的包裹好的函数赋给clac,那么calc()的法力就和上例calc_spend_time(calc())功用相符.

 1 import time
 2 def showtime(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 @showtime  #foo = showtime(foo)
12 def foo():
13     print('foo..')
14     time.sleep(3)
15 
16 def doo():
17     print('doo..')
18     time.sleep(2)
19 
20 print(foo.__name__)
21 print(doo.__name__)
def decorate(func):
    print('running decorate', func)
    def decorate_inner():
        print('running decorate_inner function')
        return func()
    return decorate_inner

@decorate
def func_1():
    print('running func_1')

if __name__ == '__main__':
    print(func_1)
    #running decorate <function func_1 at 0x000001904743DEA0>
    # <function decorate.<locals>.decorate_inner at 0x000001904743DF28>
    func_1()
    #running decorate_inner function
    # running func_1

上面包车型大巴例子正是装饰器的概念,包装函数的函数.事实上上边包车型客车例子还足以更简明

1.清楚装饰器的前提希图

装饰器在Python使用那样方便都要归因于Python的函数能像日常的对象肖似能相提并论参数字传送递给其余函数,可以被赋值给别的变量,能够作为重临值,能够被定义在别的三个函数内。

import datetime
def calc_add(a, b):
 start_time = datetime.datetime.now()
 result = a   b
 end_tiem = datetime.datetime.now()
 print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return result
calc_add(1, 2)

带参数的被点缀的函数

import time
def time_logger(flag=0):
    def show_time(func):
        def wrapper(*args, **kwargs):
            start_time = time.time()
            func(*args, **kwargs)
            end_time = time.time()
            print('spend %s' % (end_time - start_time))
            if flag:
                print('将这个操作的时间记录到日志中')
        return wrapper
    return show_time

@time_logger(flag=1)
def add(*args, **kwargs):
    time.sleep(1)
    sum = 0
    for i in args:
        sum  = i
    print(sum)
add(1, 2, 5)

带参数的函数装饰器

 1 import time
 2 def showtime(func):
 3     def wrapper(a, b):
 4         start_time = time.time()
 5         func(a,b)
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 @showtime #add = showtime(add)
12 def add(a, b):
13     print(a b)
14     time.sleep(1)
15 
16 @showtime #sub = showtime(sub)
17 def sub(a,b):
18     print(a-b)
19     time.sleep(1)
20 
21 add(5,4)
22 sub(3,2)

functools.wraps使用装饰器非常的大地复用了代码,可是他有二个毛病正是原函数的元新闻不见了,比如函数的docstring、__name__、参数列表,先看例子:

def foo():
    print("hello foo")
print(foo.__name__)# foo

def logged(func):
    def wrapper(*args, **kwargs):
        print (func.__name__   " was called")
        return func(*args, **kwargs)
    return wrapper

@logged
def cal(x):
    resul=x   x * x
    print(resul)

cal(2)
#6
#cal was called
print(cal.__name__)# wrapper
print(cal.__doc__)#None
#函数f被wrapper取代了,当然它的docstring,__name__就是变成了wrapper函数的信息了。

好在我们有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

from functools import wraps

def logged(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(func.__name__   " was called")
        return func(*args, **kwargs)
    return wrapper

@logged
def cal(x):
    return x   x * x

print(cal.__name__)  # cal

使用装饰器会时有爆发大家兴许不希望现身的副功能, 举个例子:改动被修饰函数称号,对于调节和测量检验器或然目的类别化器等急需使用内全省统编写制定的那多少个工具,大概会不能够平常运作;

骨子里调用装饰器后,会将同多个效应域中原本函数同名的丰富变量(比方上面包车型大巴func_1卡塔 尔(英语:State of Qatar),重新赋值为装饰器再次回到的对象;使用@wraps后,会把与中间函数(被修饰函数,比方下边包车型大巴func_1卡塔 尔(英语:State of Qatar)相关的重大元数据总体复制到外围函数(例如下边包车型地铁decorate_inner)

from functools import wraps

def decorate(func):
    print('running decorate', func)
    @wraps(func)
    def decorate_inner():
        print('running decorate_inner function', decorate_inner)
        return func()
    return decorate_inner

@decorate
def func_1():
    print('running func_1', func_1)

if __name__ == '__main__':
    func_1()

#输出结果
#running decorate <function func_1 at 0x0000023E8DBD78C8>
# running decorate_inner function <function func_1 at 0x0000023E8DBD7950>
# running func_1 <function func_1 at 0x0000023E8DBD7950>

 

*args:把具有的参数按现身顺序打包成list
**kargs:把装有的key=value方式的参数打包成叁个dict

以下是八个wraps的例证:

相比函数装饰器,类装饰器械有灵活度大、高内聚、封装性等优点。使用类装饰器还足以注重类内部的__call__措施,当使用 @ 情势将装饰器附加到函数上时,就能够调用此办法。

import time

class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        start_time=time.time()
        self._func()
        end_time=time.time()
        print('spend %s'%(end_time-start_time))

@Foo  #bar=Foo(bar)
def bar():
    print ('bar')
    time.sleep(2)

bar()    #bar=Foo(bar)()>>>>>>>没有嵌套关系了,直接active Foo的 __call__方法

规范库中有两种装饰器

比如:装饰格局的函数有property, classmethod, staticmethod; functools模块中的lru_cache, singledispatch,  wraps 等等

from functools class="Apple-converted-space"> import class="Apple-converted-space"> lru_cache

from functools class="Apple-converted-space"> import class="Apple-converted-space"> singledispatch

from functools class="Apple-converted-space"> import class="Apple-converted-space"> wraps

 

import datetime
def calc_spend_time(func):
 def new_func(*args, **kargs):
  start_time = datetime.datetime.now()
  result = func(*args, **kargs)
  end_tiem = datetime.datetime.now()
  print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
 return new_func
@calc_spend_time
def calc_add(a, b):
 return a   b
@calc_spend_time
def calc_diff(a, b):
 return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)

2.装饰器:无参/带参的被点缀函数,无参/带参的装潢函数

通过args 和 *kwargs 传递被修饰函数中的参数

语法糖

1 def test(name):
2     def test_in():
3         print(name)
4     return test_in
5 
6 func = test('whyz')
7 func()

带参数的棉被服装饰函数 

愿意本文所述对我们Python程序设计有着帮衬。

类装饰器:一般依据类内部的__call__方法

带参数的装饰器

class Human(object):
 """docstring for Human"""
 def __init__(self, value):
  super(Human, self).__init__()
  self._age = value
 @property
 def age(self):
  return self._age
human = Human(20)
print human.age

结果为:

import time
# 定长
def show_time(f):
    def inner(x,y):
        start = time.time()
        f(x,y)
        end = time.time()
        print('spend %s'%(end - start))
    return inner

@show_time
def add(a,b):
    print(a b)
    time.sleep(1)

add(1,2)

要是大家必要知道函数的部分万分信息,比如函数小编,可以经过给装饰器函数增添参数来达成.

注解:wraps自己也是一个装饰器,他能把函数的元音讯拷贝到装饰器函数中**使得装饰器函数与原函数有平等的元新闻

未来有八个新的须求,希望得以记录下函数的试行时间,于是在代码中增加日志代码:

 

4.python3的放权装饰器

1.

 1 import time
 2 def showtime(func):
 3     def wrapper():
 4         start_time = time.time()
 5         func()
 6         end_time = time.time()
 7         print('spend is {}'.format(end_time - start_time))
 8 
 9     return wrapper
10 
11 @showtime  #foo = showtime(foo)
12 def foo():
13     print('foo..')
14     time.sleep(3)
15 
16 @showtime #doo = showtime(doo)
17 def doo():
18     print('doo..')
19     time.sleep(2)
20 
21 foo()
22 doo()

1.职位不当的代码->不要在装饰器之外增多逻辑功用
2.不可能装饰@staticmethod 也许 @classmethod已经装修过的法子
3.装饰器会对原函数的元音讯实行改良,举例函数的docstring,__name__,参数列表:

 1 import time
 2 def time_logger(flag = 0):
 3     def showtime(func):
 4         def wrapper(a, b):
 5             start_time = time.time()
 6             func(a,b)
 7             end_time = time.time()
 8             print('spend is {}'.format(end_time - start_time))
 9             
10             if flag:
11                 print('将此操作保留至日志')
12 
13         return wrapper
14 
15     return showtime
16 
17 @time_logger(2)  #得到闭包函数showtime,add = showtime(add)
18 def add(a, b):
19     print(a b)
20     time.sleep(1)
21 
22 add(3,4)

正文参照他事他说加以考察:

本文由时时app平台注册网站发布于编程知识,转载请注明出处:Python装饰器(decorator)定义与用法精解

关键词: