更多课程 选择中心


Python培训

400-111-8989

Python 装饰器详解


代码要遵循开发封闭原则,虽然这个原则是用于面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

  • 封闭:已实现的功能代码块,已经写好的函数不要更改

  • 开放:对扩展开放,

而这正好可以用装饰器来实现。


Python 装饰器用于修改函数。

装饰器本质上是一个函数,它将被装饰的函数作为参数,然后用其返回的函数来替换那个被装饰的函数


1,最基本的装饰器

>>> def outer(func):

           def inner():

                 print("change~"+func())

                 ret = func()  # 1

                 return ret +"~1"

           return inner

>>> def foo():

         return "foo"

>>> foo = outer(foo)  #2

>>> foo()

change~foo

'foo~1'

# 下面语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约#翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种#语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加#程序的可读性,从而减少程序代码出错的机会。
#只有CPU的微代码不是语法糖,其余代码包括机器语言都是语法糖

>>> @outer

def foo():

     return "foo"

>>> foo()

change~foo 

'foo~1'

请仔细看这个装饰器示例。首先,定义了一个带单个参数 func 的名为 outer 的函数。然后在 outer 内部定义了一个内嵌函数 inner。inner 函数将打印一行字符 串 ,用来直观的告诉读者这里对要修改的函数进行了修改(change~foo)。并 在 #1 处获取其返回值。在每次 outer 被调用时,func 的值可能都会不同,但不论 func 是什么函数,都将调用它。最后,inner 返回 func() 的返回值加"~ 1"。在 #2 处可以看到,当调用赋值给 foo 的返回函数时,得到的是一行文本输出和返回值 'foo~1'而非期望的调用foo 的返回值 "foo"。

们可以说等号左边的foo是原foo的装饰版 ,outer将函数foo装修一新了。


2,注册装饰器

_functions= {}

def register(f):

      global _functions

      _functions[f.__name__] = f

      return f

@register

def foo():

     return "bar"

在这个例子中,函数被注册并存储在一个字典里,以便后续可以根据函数名字提取函数。


3,被装饰函数带一个固定参数的装饰器      

import time

def decorator(fun):    def wrapper(name):        start = time.time()        fun(name)        runtime = time.time()-start

       print (runtime)

   return wrapper

@decorator

def do_something(name):

   for i in range(1000000):

       pass    print("play game "+ name)


do_something("san guo sha") 

结果如下:

play game san guo sha

0.109375

实现很简单, 就是给wrapper函数加入相同的参数


4,被装饰函数带二个固定参数的装饰器 

import time

def decorator(fun):

    def wrapper(name1,name2):

        start = time.time()

        fun(name1,name2)

        runtime = time.time()-start

        print (runtime)

    return wrapper

@decorator

def do_something(name1,name2):

    for i in range(1000000):

        pass

    print ("play game "+name1+" & "+name2)

   

do_something("san guo sha","game2")

结果如下:

play game san guo sha & game2

0.109375

5. 目标函数带不固定参数的装饰器

import time

def decorator(fun):

    def wrapper(*args, **kwargs):

        start = time.time()

        fun(*args, **kwargs)

        runtime = time.time()-start

        print (runtime)

    return wrapper

@decorator

def do_something(name):

    for i inrange(1000000):

        pass

    print ("play game " + name)

@decorator

def do_something2(user, name):

    for i inrange(1000000):

        pass

    print (user+" play game " + name)

   

do_something("san guo sha")

do_something2("wang xiao er","san guo sha")

结果如下:

play game san guo sha

0.109375

wang xiao er play game san guo sha

0.125


6. 让装饰器带参数

import time

defdecorator(max):

    def_decorator(fun):

        defwrapper(*args, **kwargs):

            start = time.time()

            for i inrange(max):

                fun(*args, **kwargs)

            runtime = time.time()-start

            print (runtime)

        return wrapper

    return _decorator

@decorator(2)

def do_something(name):

    for i inrange(1000000):

        pass

    print ("play game " + name)

    

do_something("san guo sha") 

运行结果如下:

play game san guo sha

play game san guo sha

0.25

等同于下面

import time

defdecorator(max):

    def_decorator(fun):

        defwrapper(*args, **kwargs):

            start = time.time()

            for i inrange(max):

                fun(*args, **kwargs)

            runtime = time.time()-start

            print (runtime)

        return wrapper

    return _decorator

  

def do_something(name):

    for i inrange(1000000):

        pass

    print ("play game " + name)

#@decorator(2)

do_something= decorator(2)(do_something)    

do_something("san guo sha")

play game san guo sha

play game san guo sha

0.265625


7. 一个函数可以被多个装饰器装饰

def d1(func):

    def inner(*args,**kwargs):

        # 验证1

        return func(*args,**kwargs)

    return inner

 

def (func):

    def inner(*args,**kwargs):

        # 验证1

        return func(*args,**kwargs)

    return inner

  

@d1

@d2

def f(arg1,arg2,arg3):

    print ('f')

f(1,2,3)

运行结果如下:

f

相当于:

def d1(func):

    def inner(*args,**kwargs):

        # 验证1

        return func(*args,**kwargs)

    return inner


def (func):

    def inner(*args,**kwargs):

        # 验证1

        return func(*args,**kwargs)

    return inner


def f(arg1,arg2,arg3):

    print ('f')

f = d1(d2(f))

f(1,2,3)

运行结果如下:

f

另外形式:

@f1(arg)
@f2 def func(): pass

相当于

def func(): pass func = f1(arg)(f2(func))

8. 类也可以装饰:就像装饰函数一样

@f1(arg)
@f2 class Foo: pass

大致相当于

class Foo: pass Foo = f1(arg)(f2(Foo))

装饰器表达式的计算规则与函数装饰器的计算规则相同。然后将结果绑定到类名。

预约申请免费试听课

填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!

上一篇:敲黑板!Python与人工智能到底是什么关系?
下一篇:自学python的学习路线图和阶段

2021年Python全套免费视频教程在哪里?

Python编程学习路线

Python最高有几级?

人工智能与语音遥控的区别?

  • 扫码领取资料

    回复关键字:视频资料

    免费领取 达内课程视频学习资料

Copyright © 2023 Tedu.cn All Rights Reserved 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有

选择城市和中心
黑龙江省

吉林省

河北省

湖南省

贵州省

云南省

广西省

海南省