zoukankan      html  css  js  c++  java
  • 搞定三大神器之 Python 装饰器

    学会 Python 装饰器

    装饰器,几乎各大Python框架中都能看到它的身影,足以表明它的价值!它有动态改变函数或类功能的魔力!

    本专题的目录:

    • 学会 Python 装饰器

      • 1 什么是装饰器

      • 2 装饰器的结构

      • 3 为什么要这样

      • 4 装饰一个函数

      • 5 装饰一个类

      • 6 装饰器层叠

      • 7 温馨提醒

      • 总结

    1 什么是装饰器

    对于受到封装的原函数比如f来说,装饰器能够在f函数执行前或者执行后分别运行一些代码。

    2 装饰器的结构

    装饰器也是一个函数,它装饰原函数f或类cls后,再返回一个函数g

    装饰一个函数:

    def decorator(f):
      # 定义要返回的函数
      def g():
        print('函数f执行前的动作')
        f()
        print('函数f执行后的动作')
      return g

    装饰一个类:

    def decorator(cls):
      # 定义要返回的函数
      def g():
        print('类cls执行前的动作')
        f()
        print('类cls执行后的动作')
      return g

    使用装饰器很简单,@+自定义装饰器 装饰要想装饰的函数。

    3 为什么要这样

    要想理解装饰器为什么要有这种结构,要首先想明白装饰器的目标是什么。

    它的价值在于为原函数f增加一些行为,前提必须不能破坏函数f,所以肯定不能改变f的内部结构,所以只能在调用f前后定义一些行为。

    同时,装饰器函数decorator返回值又是什么?你可以思考下,返回一个函数是再好不过的了,它包装了原函数f.

    4 装饰一个函数

    printStar函数接收一个函数f,返回值也是一个函数,所以满足装饰器的结构要求,所以printStar是一个装饰器。

    def printStar(f):
        def g():
            print('*'*20)
            f()
            print('*'*20)
        return g

    printStar装饰器实现f函数执行前、后各打印20个*字符。

    使用printStar:

    @printStar
    def f():
        print('hello world')

    调用:

    if __name__ == '__main__':
       ### 改变函数功能
       f()

    打印结果:

    ********************
    hello world
    ********************

    可以很方便的装饰要想装饰的其他函数,如下:

    @printStar
    def g():
        print('welcome to Python')

    5 装饰一个类

    除了可以装饰函数f外,还可以装饰类cls,两者原理都是一样的。

    下面给出一个装饰器实现单例模式的例子,所谓单例就是类只有唯一实例,不能有第二个。

    def singleton(cls):
       instance = {}

       def get_instance(*args, **kwargs):
           if cls not in instance:
               instance[cls] = cls(*args, **kwargs)
           return instance[cls]
       return get_instance

    定义字典instance,键值对分别为类和实例,这样确保只cls()一次。

    使用装饰器singleton修饰类:

    @singleton
    class CorePoint:
       pass

    测试:

    if __name__ == '__main__':
       ### 改变类的功能
       c1 = CorePoint()
       c2 = CorePoint()
       print(c1 is c2) # True

    6 装饰器层叠

    上面原函数f不仅能被一个装饰器修饰,还能被n多个装饰器修饰。

    下面再定义一个装饰器printLine,被修饰函数执行前后打印20个 -

    def printLine(f):
        def g():
            print('-'*20)
            f()
            print('-'*20)
        return g

    使用上文定义好的printStarprintLine同时装饰函数f:

    @printStar
    @printLine
    def f():
        print('hello world')

    此时再调用函数f:

    if __name__ == '__main__':
       ### 改变函数功能
       f()

    打印结果:

    ********************
    --------------------
    hello world
    --------------------
    ********************

    f被装饰后,先打印*,再打印 -

    层叠多一层,原函数f就变强大一层。使用装饰器,还能实现功能抽离,进一步实现松耦合。

    7 温馨提醒

    打印原函数f的名字__name__,结果为f

    In [1]: def f(): 
       ...:     pass 

    In [4]: f.__name__                                                              
    Out[4]: 'f'

    但是,被装饰后函数名字f变为g,这不是我们希望的!

    @printStar
    def f():
      pass

    f()
    f.__name__ # g

    Python提供的解决方案:使用functools模块中的wraps装饰器:

    from functools import wraps

    def printStar(f):
        @wraps(f)
        def g():
            print('*'*20)
            f()
            print('*'*20)
        return g

    此时再打印被装饰后f的名字,显示f,正常!

    有相同爱好的可以进来一起讨论哦:企鹅群号:1046795523

    学习视频资料:http://www.makeru.com.cn/live/1392_1164.html?s=143793

  • 相关阅读:
    Python中if __name__ == '__main__':作用
    mac 用macports给python装opencv
    (转)学习&使用技术的四种层次
    图像处理入门,一些简单的基于像素几何变换和实现
    基于水平投影,垂直投影的字符图像分割思路和代码实现
    转:Cannot make a static reference to the non-static解决办法
    BP神经网络学习和c++例子程序代码
    python中初始化一个数组用来存储多张图片
    假期第二周周总结
    假期第一周周总结
  • 原文地址:https://www.cnblogs.com/jinwenyi/p/13719471.html
Copyright © 2011-2022 走看看