python中的装饰器理解

孤街浪徒 提交于 2019-12-05 08:39:45

python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能。 

这个函数的特殊之处在于它的返回值也是一个函数,这个函数是内嵌“原“”函数的函数。

之前拓展函数的做法是侵入原函数进行拓展修改,例如:

原始函数:

      import time

  def f():
    print("hello")
    time.sleep(1)
    print("python")  
 
修改为记录下这个函数执行的总时间,改动原来的代码:
   
      import time
 
     def f():

          begintime = time.time()
          print("hello")
          time.sleep(1)
     print("python")
          endtime = time.time()

          totaltime = (endtime - begintime )*1000
          print("time is %d ms" %totaltime )

 

 

使用闭包函数的用法如下:

import time

def test(func):

  begintime = time.time()

  f()

  endtime = time.time()

  totaltime = (endtime - begintime) * 1000

  print("执行时间:%d ms"%tataltime)

 

def f():

  print("hello")

  time.sleep(1)

  print("python")

if __name == "__main__":

  test(f)

这种方式的缺点是:但是想要拓展这一千万个函数功能,就是要执行一千万次test()函数。

 

使用装饰器来实现如下:

import time

def test(f):

  def func():

    begintime = time.time()

    f()

    endtime = time.time()

    totaltime = (endtime-begintime) * 1000

    print("执行时间:%d ms"%tataltime)

  return func

@test

def f():

  print("hello")

  time.sleep(1)

  print("python")

 

if __name == "__main__":

  f()

这里的test函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数f()就在返回函数func()的内部执行。然后在函数f()前面加上@test,

f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多”的函数了(不需要重复执行原函数)。 

 

扩展1:带有固定参数的装饰器

import time

def test(f):

  def func(a,b):

    begintime = time.time()

    f(a,b)

    endtime = time.time()

    totaltime = (endtime-begintime) * 1000

    print("执行时间:%d ms"%tataltime)

  return func

 @test

def f(a,b):

  print("hello")

  time.sleep(1)

  print("python")

  time.sleep(1)

  print(a+b)

 if __name == "__main__":

  f(3,4)

 

扩展2:无固定参数的装饰器:

import time

def test(f):

  def func(*args,**kwargs):

    begintime = time.time()

    f(*args,**kwargs)

    endtime = time.time()

    totaltime = (endtime-begintime) * 1000

    print("执行时间:%d ms"%tataltime)

  return func

@test

def f(a,b):

  print("hello")

  time.sleep(1)

  print("python")

  time.sleep(1)

  print(a+b)

@test

def f2(a,b,c):

  print("hello")

  time.sleep(1)

  print("python")

  time.sleep(1)

  print(a+b+c)

 if __name == "__main__":

  f(3,4)

  f2(5,6,7)

 

扩展3:使用多个装饰器装饰一个函数

import time

def test1(f):

  def func(*args,**kwargs):

    print("test1")

    begintime = time.time()

    f(*args,**kwargs)

    endtime = time.time()

    totaltime = (endtime - begintime) * 1000

    print("执行时间:%d ms"%tataltime)

    print("test1 end")

  return func

def test2(f):

  def func(*args,**kwargs)

    print("test2 begin")

    f(*args,**kwargs)

    print("test2 end")

  return func

@test1

@test2

def f(a,b):

  print("hello")

  time.sleep(1)

  print("python")

  time.sleep(1)

  print(a+b+c)

if __name__ == "__main__":

  f(3,4)

执行结果:

 test1

 test2 begin

hello
python
7
test2 end
执行时间:%d ms"%tataltime
test1 end

装饰器调用顺序

装饰器是可以叠加使用的,那么使用装饰器以后代码是啥顺序呢?

对于Python中的”@”语法糖,装饰器的调用顺序与使用 @ 语法糖声明的顺序相反。

在这个例子中,”f(3, 4) = test1(test2(f(3, 4)))”。

 

Python内置装饰器

在Python中有三个内置的装饰器,都是跟class相关的:staticmethod、classmethod 和property。

  • staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用
  • classmethod 与成员方法的区别在于所接收的第一个参数不是 self (类实例的指针),而是cls(当前类的具体类型)
  • property 是属性的意思,表示可以通过通过类实例直接访问的信息
 

  

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!