评论

收藏

[JavaScript] 对Python装饰器的个人理解方法

开发技术 开发技术 发布于:2021-06-23 22:22 | 阅读数:478 | 评论:0

0.说明
         
        在自己好好总结并对Python装饰器的执行过程进行分解之前,对于装饰器虽然理解它的基本工作方式,但对于存在复杂参数的装饰器(装饰器和函数本身都有参数),总是会感到很模糊,即使这会弄懂了,下一次也很快忘记,其实本质上还是没有多花时间去搞懂其中的细节问题。

        虽然网络上已经有很多这样的文章,但显然都是别人的思想,因此自己总是记不牢,所以花点时间自己好好整理一下。

        最近在对《Python核心编程》做总结,收获了不少,下面分享一下我自己对于Python装饰器的理解,后面还提供了一个较为复杂的Python装饰器的执行过程的分解,可以参考一下。





1.Python装饰器的出现


         在没有装饰器之前,如果要在类中定义一个静态方法,需要使用下面的方法:
class MyClass(object):
def staticFoo():
    staticFoo = staticmethod(staticFoo)</pre><p style="white-space:normal;">    即要在该静态方法中加入类似staticmethod()内建函数将该方法转换为静态方法,这显然非常麻烦,而有了装饰器之后,就可以写成下面这样:<pre class="brush:python;toolbar:false">class MyClass(object):
  @staticmethod
  def staticFoo():
    pass</pre><p style="white-space:normal;">    这样就简洁很多了。<p style="white-space:normal;"><br /><p style="white-space:normal;"><br /><p style="white-space:normal;"><span style="color:rgb(255,0,0);"><strong>2.Python装饰器类型与理解</strong></span><p style="white-space:normal;"><br /><p style="white-space:normal;"><span style="line-height:0px;"></span><span style="color:rgb(0,0,0);"><strong>(1)无参数装饰器  </strong></span><span style="line-height:0px;"></span><span style="color:rgb(0,112,192);">  </span><ul class="list-paddingleft-2" style="width:697.297px;white-space:normal;"><li><span style="color:rgb(192,0,0);">一个装饰器</span></li></ul><p style="white-space:normal;">    下面的情况:<pre class="brush:python;toolbar:false">@f
  def foo():

  pass
        其实就相当于:
def foo():
pass
foo = g(foo)

  • 多个装饰器

        下面的情况:
@g
@f
def foo():
pass
        就相当于:
def foo():
pass
foo = g(f(foo))


(2)含参数装饰器

  • 带有参数的一个装饰器

        下面的情况:
@decomaker(deco_args)
def foo():
pass
        就相当于:
def foo():
pass
foo = decomaker(deco_args)(foo)
        用这样的思想去理解就非常好理解了:decomaker()用deco_args做了些事并返回函数对象,而该函数对象正是以foo作为其参数的装饰器

        下面多个装饰器的例子也是按这样的思想去理解。

  • 带有参数的多个装饰器

        下面的情况:
@deco1(deco_arg)
@deco2()
def foo():
pass
        就相当于:
def foo():
pass
foo = deco1(deco_arg)(deco2(foo))





3.Python装饰器执行过程的手动分解


        OK,有了上面的理论基础,理解下面一个较为复杂的装饰器就很容易了:
from functools import wraps
def log(text):
def decorator(func):
    @wraps(func)          #it works like:wraper.__name__ = func.__name__
    def wrapper(*args, **kwargs):
      print '%s %s():' % (text, func.__name__)
      return func(*args, **kwargs)
    return wrapper
  return decorator
  @log('Hello')
  def now(area):
  print area, '2016-01-23'

  now('Beijing')

  print 'The name of function now() is:', now.__name__
        执行如下:
/usr/bin/python2.7 /home/xpleaf/PycharmProjects/decorator_test/dec10.py
Hello now():
Beijing 2016-01-23
The name of function now() is: now

对于该程序的执行过程,可以分析如下:
1.先执行log('Hello')函数,此时返回了一个新的函数,只不过其中的text变量被替换为'Hello',所以用来装饰now函数的新的装饰器如下:
def decorator(func):
@wraps(func)          #it works like:wraper.__name__ = func.__name__
def wrapper(*args, **kwargs):
    print '%s %s():' % ('Hello', func.__name__)
    return func(*args, **kwargs)
  return wrapper</pre><p style="margin-top:0px;margin-bottom:0px;padding:0px;white-space:normal;">2.所以此时的now函数,就相当于:<pre class="brush:python;toolbar:false">now = decorator(now)</pre><p style="margin-top:0px;margin-bottom:0px;padding:0px;white-space:normal;">3.即now就相当于:<pre class="brush:python;toolbar:false">def now(*args, **kwargs):
  print '%s %s():' % ('Hello', old_now.__name__)
  return old_now(*args, **kwargs)
# 现在的函数名称变为了now而不是wrapper,是因为使用了wraps装饰器
   所以,输出的结果也就非常好理解了。

        关于wraps,它也是一个装饰器,使用它的作用是,被我们用自定义装饰器修改后的函数,它的函数名称,即func.__name__跟原来是一样的,而它的工作原理正如上面所提及的,即:
wraper.__name__ = func.__name__
        也就是说,使用wraps可以不改变原来函数的属性,当然,上面只是简单说明了一下其工作原理,详细的可以参考wraps的源代码。
        在GitHub上给出了10个理解装饰器的例子,可以参考一下:https://github.com/xpleaf/decorator
        本文选中我的《Python回顾与整理》系列博文中的《Python回顾与整理9:函数和函数式编程》


关注下面的标签,发现更多相似文章