精华内容
下载资源
问答
  • 主要介绍了简单了解python装饰器原理及使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 本文实例讲述了Python装饰器原理与简单用法。分享给大家供大家参考,具体如下: 今天整理装饰器,内嵌的装饰器、让装饰器带参数等多种形式,非常复杂,让人头疼不已。但是突然间发现了装饰器的奥秘,原来如此简单。...
  • #!/usr/bin/env python#coding:utf-8"""装饰器实例拆解"...')return funcdef tv00(name):print('00你的用户是:%s' %name)# 装饰器的精简工作原理解释:tv = login00(tv00) #...

    #!/usr/bin/env python

    #coding:utf-8

    """

    装饰器实例拆解

    """

    def login00(func):

    print('00请通过验证用户!')

    return func

    def tv00(name):

    print('00你的用户是:%s' %name)

    # 装饰器的精简工作原理解释:

    tv = login00(tv00) # 返回tv函数的对象,赋值给tv

    tv('yh00') # 调用执行tv函数

    # 魔方版装饰器

    def login01(func):

    print('01请通过验证用户!')

    return func

    @login01

    def tv01(name):

    print('01你的用户是:%s' %name)

    tv01('yh01')

    # 存在一个问题,调用执行tv函数前,会执行login函数的print语句

    # 改进版装饰器

    def login02(func):

    def inner(arg):

    print('02请通过验证用户!')

    func(arg)

    return inner

    def tv02(name):

    print('02你的用户是:%s' %name)

    tv02 = login02(tv02) # 返回inner函数的对象,赋值给tv02;并把 tv02函数的对象 传递给 login02函数的形参 func

    tv02('yh02') # 调用执行tv02函数,把实参:yh02 传给 形参arg;执行tv02('yh02')

    # 改进 魔方版 版装饰器

    def login03(func):

    def inner(arg):

    print('03请通过验证用户!')

    func(arg)

    return inner

    @login03

    def tv03(name):

    print('03你的用户是:%s' %name)

    tv03('yh03')

    展开全文
  • 作者简介曾凡伟,携程信息安全部高级安全...本文将介绍如何使用 Python 进阶编程之装饰器,来帮助您写出更加精炼可读的代码。全文主要分为四个部分:第一部分:尝鲜,通过讲解一个简单的装饰器例子,让您对装饰...

    作者简介

    曾凡伟,携程信息安全部高级安全工程师,2015年加入携程,主要负责安全自动化产品的设计和研发,包括各类扫描器、漏洞管理平台、安全 SaaS 平台等。

    Python 是一门追求优雅编程的语言,它很容易上手,也很容易写出意大利式的代码。本文将介绍如何使用 Python 进阶编程之装饰器,来帮助您写出更加精炼可读的代码。

    全文主要分为四个部分:第一部分:尝鲜,通过讲解一个简单的装饰器例子,让您对装饰器的用法和作用有一个初步的感性认识;

    第二部分:揭开面纱,将介绍装饰器抛开语法糖的使用方法,帮助您理解装饰器的本质原理;

    第三部分:趁热打铁,将介绍装饰器在工作当中的实践用法,对应介绍的 retry 装饰器您可直接应用到项目代码中;

    第四部分:更进一步,将介绍装饰器更多的高级用法,帮助您全方位掌握装饰器。

    尝鲜

    我们先来看一个简单的装饰器例子。首先定义一个装饰器 log:

    def log(f):

    def wrapper():

    print "before"

    f()

    print "after"

    return wrapper

    使用装饰器 log 来装饰 greeting 函数,并调用之:

    @log

    def greeting():

    print "Hello, World!"

    greeting()

    输出结果:

    before

    Hello, World!

    after

    可以看到,使用装饰器我们实现了在函数 greeting 前后打印调试日志。

    揭开面纱

    装饰器是什么?从字面意思我们大致可以推测出来,它的作用是用来装饰的。日常生活中,大家都见过很多装饰器,比如装饰在圣诞树上的彩纸,或者套在 iPhone 外面的保护壳。保护壳的存在,并不会改变 iPhone 内部的功能,它存在的意义,在于增强了 iPhone 的抗摔性能。Python 中的装饰器也是一样的道理,它并不会改变被装饰对象的内部逻辑,而是通过一种无侵入的方式,让它获得一些额外的能力,比如日志记录、权限认证、失败重试等等。

    Python 装饰器看起来高深莫测,实际上它的实现原理非常简单。我们知道,在 Python 中一切皆对象,函数作为一个特殊的对象,可以作为参数传递给另外一个函数,装饰器的工作原理就是基于这一特性。装饰器的默认语法是使用@来调用,这实际上仅仅是一种语法糖。下面我们看看,不利用语法糖来怎么调用装饰器:

    def greeting():

    print "Hello, World!"

    greeting = log(greeting)

    把函数 greeting 作为参数传递给装饰器函数 log 就行了!对装饰器 log 来说,它接收一个函数作为入参,然后返回一个新的函数,最后再赋值给 greeting 标识符。这样便得到了一个增强功能的函数,而它的名字又和之前的保持一样。

    趁热打铁

    装饰器是一个编程利器,只需一处修改,任何被装饰的对象就可以获得额外的功能。撸起袖子,让我们来看看装饰器在编程实践中的具体应用。

    我们知道,程序跑起来后,有一些因素往往是不可控的,比如网络的连通性。为了容错,我们可能会加入 try-except 语句来捕获异常;考虑到请求失败是有一定概率的,我们或许可以通过多次重试的策略,以达到提高成功率的目的。我们先来模拟一个 non_steady 函数:

    import random

    def non_steady():

    if random.random() <= 0.5:

    # 失败的概率是 0.5

    raise Exception("died")

    else:

    # 成功的概率是 0.5

    return "survived"

    这个函数成功返回的概率是0.5。显然,单次调用的成功率太低,如果重试10次呢?计算一下:1-(0.5)^10,即成功的概率将提升到0.9990,相比单次调用的0.5,重试的成功率大 大地提升了。

    按照上面的描述,我们先通过 for 循环来提升调用 non_steady 的成功率:

    def non_steady_with_retry(times=10):

    for i in xrange(times):

    try:

    return non_steady()

    except Exception as e:

    if (i + 1) < times:

    # 尚未达到最大重试次数,默默吞掉异常

    pass

    else:

    # 连续重试,达到最大次数时还是发生异常,则抛出异常

    raise e

    提升成功率的效果达到了,但是这种实现存在几个问题:

    1、不支持无缝升级。假如函数 non_steady 在代码中被调用了 n 次,那么这意味着你需要同时修改 n 个地方(将调用 non_steady 修改为调用 non_steady_with_retry);

    2、不支持代码复用。如果你有第二个函数 non_steady1,也需要升级一下重试机制,那么这意味着同样的重试代码,你需要再重写一遍。

    再试试用装饰器来提升调用 non_steady 的成功率。定义一个 retry 装饰器:

    def retry(times=10):

    def outer(f):

    def inner(*args, **kwargs):

    for i in xrange(times):

    try:

    return f(*args, **kwargs)

    except Exception as e:

    if (i + 1) < times:

    pass

    else:

    raise e

    return inner

    return outer

    试用一下:

    import random

    @retry(10)

    def non_steady():

    if random.random() <= 0.5:

    # 失败的概率是 0.5

    raise Exception("died")

    else:

    # 成功的概率是 0.5

    return "survived"

    可以看到,只要函数前面加一行代码 @retry(10),即可为其升级重试机制。一处更改即可,无需处处担忧。同时,对于其他想要升级的函数,也只需要更改一个地方,同样的代码就无需重写多遍了。

    更进一步

    一个函数可以同时应用多个装饰器,比如下面使用两个装饰器来装饰 greeting 函数:

    @log

    @retry(10)

    def greeting():

    print "Hello, World!"

    这段代码等价于:

    def greeting():

    print "Hello, World!"

    temp = retry(10)(greeting)

    greeting = log(temp)

    可以看到,叠加的装饰器生效的顺序是从内往外的。这一点在使用的时候需要特别注意。

    Java 中的注解,语法和 Python 中的装饰器很相似,它注解的顺序,没有 Python 中装饰器这么严格。使用时注意区分下。

    除了函数,也可以用类来定义一个装饰器:

    class Log(object):

    def__init__(self, f):

    self.f = f

    def__call__(self, *args, **kwargs):

    print "before"

    self.f()

    print "after"

    类装饰器主要是通过它的__call__方法来实现的。相比函数装饰器,类装饰器具有面向对象编程所支援的一系列特点,比如高内聚、封装性和灵活度大等优点。使用类装饰器来装饰函数:

    @Log

    def greeting():

    print "Hello, World!"

    greeting()

    输出结果和使用函数装饰器一样:

    before

    Hello, World!

    after

    实际上,Python 中任何 callable 的对象都可以用来定义装饰器。

    结语

    使用 Python 装饰器,可以让你的代码更易维护,可读性也有一定提升。相信大家在日常工作中也有碰到过很多使用装饰器的场景,欢迎留言分享!人生苦短,我用 Python。

    展开全文
  • 本文实例讲述了python装饰器原理与用法。分享给大家供大家参考,具体如下: 你会Python嘛? 我会! 那你给我讲下Python装饰器吧! Python装饰器啊?我没用过哎 以上是我一个哥们面试时候发生的真实对白。 ————...
  • 我们以测量函数运行时间为例来讲一讲python装饰器的运行原理。1、使用装饰器打印函数运行时间通常我们使用 time 库来获取函数的运行时间。import time# 函数运行 2秒def func():time.sleep(2)start_time = time.time...

    一、最简单的装饰器

    装饰器是python中很基础也很实用的一个特性。通过装饰器我们可以很方便地为一些函数添加相同的功能。我们以测量函数运行时间为例来讲一讲python装饰器的运行原理。

    1、使用装饰器打印函数运行时间

    通常我们使用 time 库来获取函数的运行时间。

    import time

    # 函数运行 2秒

    def func():

    time.sleep(2)

    start_time = time.time()

    func()

    end_time = time.time()

    print('函数运行时间为:%.2fs' % (end_time - start_time))

    so easy,现在我们来思考一下:如果我们有 100个函数,怎么打印这100个函数的运行时间呢?

    总不能按照上面的写法来100次吧,这绝不是一个程序猿应该做的事,这时候装饰器就可以排上用场了。

    我们先看代码,然后再慢慢讲其中的原理。

    import time

    def timeit(func):

    def result():

    start_time = time.time()

    func()

    end_time = time.time()

    print('函数运行时间为:%.2fs' % (end_time - start_time))

    return result

    @timeit

    def func_0():

    time.sleep(2)

    # 省略98个

    @timeit

    def func_99():

    time.sleep(2)

    # 接下来直接调用这100个函数即可

    func_0()

    # ...

    使用了 timeit 装饰器的函数和没使用装饰器的原始方法效果一样,不过这只是装饰器最简单的一个应用,我们下面来看看其中的原理。

    2、timeit的运行原理

    首先,大家需要知道在python中的函数也是对象,是对象就可以作为参数传递,这是装饰器实现的基础。

    接下来我们来看看装饰器 timeit,不难看出 timeit 是一个函数。准确地说 timeit 是一个接受一个函数为参数并且返回一个函数的函数。

    听着挺拗口的,别急,看我细细道来。

    timeit 是一个函数,它接受一个参数,这个参数必须是函数(或者说可调用对象),并且 timeit 的返回结果一定是一个函数。

    看到这里大家应该对装饰器有一点了解了,原来装饰器就是接受一个函数为参数返回另一个函数的函数。

    现在我们就可以解释 timeit 的运行原理了,看下面的代码

    # 代码块1

    @timeit

    def func_0():

    time.sleep(2)

    # 代码块2

    def func_0():

    time.sleep(2)

    func_0 = timeit(func_0)

    这里的代码块1和代码块2完全等价,注意完全两个字,这说明这两段代码的效果一模一样。

    事实上代码块1就是代码块2的简写形式,因为代码块2的写法挺麻烦的,所以python的设计者加了一些语法糖,就有了代码块1的写法。

    了解了这些我们再来看看 timeit 内部

    def timeit(func):

    def result():

    start_time = time.time()

    func()

    end_time = time.time()

    print('函数运行时间为:%.2fs' % (end_time - start_time))

    return result

    在 timeit里面我们定义了一个函数 result ,函数 result 里面的内容我们很熟悉,就是打印函数 func 的运行时间。这里的 func 就是我们要装饰的函数。

    最后我们将函数 result 返回,我们再看到代码块2,返回的 result 函数替换了我们要装饰的函数 func_0,这时当我们再调用函数 func_0 时其实就是在调用函数 result。

    3、什么是闭包

    我们看一段代码:

    def outer():

    a = 0

    def inner():

    print(a)

    return inner

    func = outer()

    func()

    上面的函数和装饰器很像,以前学C语言的可能会疑惑为什么变量a在函数 outer 调用完成后仍然能够被访问。

    这和python中变量的回收机制有关,python根据变量的引用计数来判断是变量是否需要回收。

    当一个对象的引用被创建或复制时,对象的引用计数加1;当一个对象的引用被销毁时,对象的引用计数减1,如果对象的引用计数减少为0,将对象的所占用的内存释放。

    上面的例子中因为对象a的引用一直没有被销毁引用计数不为0,所以在函数 inner 里一直可以访问对象a的值。

    而且我们发现在调用过函数 outer 后只有函数 inner 可以访问对象a。

    这就相当于为函数 inner添加了一个私有的命名空间,而且只有函数 inner 可以访问这个命名空间,这就是python中的闭包。

    装饰器就是利用了闭包的原理,所以我们说装饰器就是是闭包也是完全没有问题的。

    二、带参数的装饰器

    我们可能看到过这样的装饰器

    @decorator('arg','arg2')

    def func():

    # do something

    pass

    在一些代码中我们发现有些装饰器是有参数的,这样可以带参数的装饰器是怎么实现的呢?下面我就和大家讲一讲带参数的装饰器是怎么实现的。

    在了解了装饰器的原理之后我们知道装饰器其实就是一个返回一个函数的函数。

    于是我们就想:既然有返回函数的函数,那有没有返回装饰器的函数呢?当然是有的!

    事实上,上面提到的带参数的装饰器就是一个返回装饰器的函数。

    其中的原理也很简单,圆括号表示函数调用,而我们的程序都是从右到左执行的,所以在程序运行的时候 @ 后面的应该是 decorator 返回的装饰器。

    说完原理,我们再来看看带参数的装饰器应该怎么写,先上代码。

    import time

    def timeit(out='函数运行时间为:%.2fs'):

    def decorator(func):

    def result():

    start_time = time.time()

    func()

    end_time = time.time()

    print(out % (end_time - start_time))

    return result

    return decorator

    @timeit('函数运行时间为:%.2fs --来自带参数的装饰器')

    def func():

    time.sleep(2)

    func() # => 函数运行时间为:2.00s --来自带参数的装饰器

    我们在原来打印函数运行时间的装饰器上添加了自定义打印语句的功能,在使用的时候和下面的代码等价。

    func = timeit('函数运行时间为:%.2fs --来自带参数的装饰器')(func)

    带参数的装饰器也是利用了闭包将参数绑定到返回的函数上。

    三、更加通用的装饰器

    前面两部分讲了装饰器的原理,这一部分就讲讲要写出一个通用的装饰器需要注意的问题。

    首先就是参数的问题,装饰器返回的函数不是原来的函数,函数的签名也就和原来的函数签名不一样。

    当我们还是按照来的方式去调用函数就有可能会出问题,我们通过一个例子来看一下。

    def decorator(func):

    def result(a):

    print(a)

    func()

    return result

    @decorator

    def func(a,b,c):

    print(a,b,c)

    func(1, 2, 3)

    # => TypeError: result() takes 1 positional argument but 3 were given

    这里报错是因为装饰器返回的函数只接受一个参数,我们还按照调用 func 的方式来调用 result当然会报错。

    展开全文
  • 本文实例讲述了Python装饰器原理与用法。分享给大家供大家参考,具体如下: 1、装饰器的本质是函数,主要用来装饰其他函数,也就是为其他函数添加附加功能 2、装饰器的原则: (1) 装饰器不能修改被装饰的函数的源代码...
  • 本文实例讲述了Python装饰器原理与基本用法。分享给大家供大家参考,具体如下: 装饰器: 意义:在不能改变原函数的源代码,和在不改变整个项目中原函数的调用方式的情况下,给函数添加新的功能 由于不允许改变函数...
  • 本文实例讲述了Python 装饰器原理、定义与用法。分享给大家供大家参考,具体如下: Python 装饰器 一、何为装饰器 1、在函数中定义函数 在函数中定义另外的函数,就是说可以创建嵌套的函数,例子如下 def sayHi...
  • 了解装饰器是如何实现的,远比会写装饰器更重要,简单的说装饰器就是接收一个函数对象,然后先执行前置操作,再执行函数,再执行后置操作; 这么说可能有些抽象,或者举一个不那么恰当的比较贴近生活的例子; 假设你...
  • 本文实例讲述了Python函数装饰器原理与用法。分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值也是一...
  • python中的装饰器python解释器直接支持,其定义形式如下:@decoratordef core_service:....要理解上述代码的含义,我们从自定义函数装饰器原理出发。以下是示例代码:importos, sysdefdecor_wrappe...

    装饰器(Decorator)是面向对象设计模式的一种,这种模式的核心思想是在不改变原来核心业务逻辑代码的情况下,对函数或类对象进行额外的修饰。python中的装饰器由python解释器直接支持,其定义形式如下:

    @decorator

    def core_service:

    ....

    要理解上述代码的含义,我们从自定义函数装饰器的原理出发。以下是示例代码:

    importos, sys

    defdecor_wrapper(func):

    defdecorator():

    print("Get in decorator")

    func()

    returndecorator

    defcore_service():

    print("Get in core_service")

    if__name__ == "__main__":

    core_service = decor_wrapper(core_service)

    core_service()

    运行结果:

    Get in decorator

    Get in core_service

    原理:以上代码是一个简单的函数装饰器示例。核心代码逻辑是core_service()函数,真正的装饰器函数是定义在decor_wrapper()函数内部的decorator()函数,这个函数实现了装饰功能并调用了核心业务功能。decor_wrapper()函数仅仅是一个包装函数,用来返回装饰器的引用。core_service最终引用的是decor_wrapper()函数返回的装饰器函数,最后调用core_service()函数其实执行的就是装饰器函数decorator()。

    以上编写装饰器代码的步骤比较多,且模式是固定的,因此python提供了语言级别的封装。上述代码可以抽象成如下形式,结果同上:

    importos, sys

    defdecor_wrapper(func):

    defdecorator():

    print("Get in decorator")

    func()

    returndecorator

    @decor_wrapperdefcore_service():

    print("Get in core_service")

    if__name__ == "__main__":

    core_service()

    @decor_wrapper

    defcore_service():

    print("Get in core_service")

    python解释器会将这段代码解析成以下形式:

    defcore_service():

    print("Get in core_service")

    core_service = decor_wrapper(core_service)

    通过以上分析,我们已经清楚了装饰器原理。真实的装饰器还会带有各种参数,实现各种复杂的功能,这些都是建立在这个基本原理的基础之上。下面我们再通过一个类装饰器的示例代码来结束这个主题:

    importos, sys

    defdecor_wrapper(cls):

    defdecorator():

    print("Get in decorator")

    returncls()

    returndecorator

    @decor_wrapperclassCore:

    def__init__(self):

    print("New Core object")

    if__name__ == "__main__":

    core = Core()

    运行结果:

    Get in decorator

    New Core object

    展开全文
  • python装饰器原理

    千次阅读 2018-03-29 20:26:07
    装饰器python里面使用非常广泛,常用的应用场景,比如可以使用装饰器来做拦截器,或者是在执行某个函数之前,执行另外一个函数,执行完毕之后在执行其他函数,使用装饰器就可以很优雅的解决这种需求。 下面通过...
  • 原理装饰器本质也是一个函数, 只不过这个函数需要遵循以下规则:入参只能有一个,类型为函数。 被装饰的函数将入会被传入这个参数返回值是必须是一个函数, 届时被调用的时候实际上调用的是返回出来的这个函数,所以...
  • 装饰器Python的一大重点和难点,其允许Python实现装饰器设计模式,可以在不改变某函数结构和调用方式基础之上,为其增加新的功能,并且最大化复用新的功能 装饰器在面向切面编程的场景中很有用,比如为函数增加...
  • 简单了解Python装饰器实现原理

    千次阅读 2018-06-12 11:27:11
    有过开发经验得朋友队装饰模式这个词应该不陌生,装饰装饰,顾名思义就是指对我们原来有得东西进行装饰,比如我们买了新房,那么我们对毛坯房的装修,就是对我们房子进行拓展,让它更加完善!同样得对于代码也是如此...
  • 主要介绍了Python @property装饰器原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,554
精华内容 6,221
关键字:

python装饰器原理

python 订阅