(博客原创作品,转载请注明出处!)

  最近接触到了Python中的decorator,metaclass,abc Module,six.add_metaclass等内容,这里做一个简单的笔记。

  主要资源:

  1. PEP3119:Abstract Base Classes

  2. abc模块:abc Moduleabc—Abstract Base Classes

  3. metaclass: “Python中metaclass解释”、浅析python的metaclassPEP3115

  4. 相关:Python 3 初探,第 2 部分: 高级主题

  5. six.add_metaclass: six Module

  

  装饰器的引入纯粹是一个“语法糖”,即让代码看起来更加易懂。装饰器引入前Python中已经存在了“class method”, "static method"等包裹函数,不使用装饰器的结果是如果一个方法要被声明为class method,那么在他的“def”语句结束后需要立即使用"classmethod"将其注册成类方法。这样有一些弊端:当代码的读者开始读这个函数的时候,他一般看不到末尾的"classmethod"语句,所以可能直到看完整个函数的定义才知道这是一个类方法,也即是最初没有装饰器时在定义的结尾对方法进行装饰的设定比较反人类;另外采用 method = classmethod(method) 方式写出来的代码,设计Python的大神们觉得 method 竟然重复出现了两次太多了,写这两次 method 的时间已经够他们喝一壶的了,所以引入了更为简洁的decorator。

  装饰器以“@”标识,实质上是一层包裹函数,即函数的函数。写在函数定义( def 语句)的前面,表示 def 语句后定义的函数受到装饰器的装饰,也就是说这个新定义的函数刚刚出生,立刻在函数定义结束的下一行代码运行装饰器给她穿点衣服遮羞。

  metaclass是“类的类”,秉承Python“一切皆对象”的理念,Python中的类也是一类对象,metaclass的实例就是类(class),自己写metaclass时需要让其继承自type对象。关于metaclass的介绍,“主要资源”中相关的链接,不做赘述。

  ABC(抽象基类),主要定义了基本类和最基本的抽象方法,可以为子类定义共有的API,不需要具体实现。

  abc模块,Python 对于ABC的支持模块,定义了一个特殊的metaclass—— ABCMeta 还有一些装饰器—— @abstractmethod 和 @abstarctproperty 。

   abc.ABCMeta 是一个metaclass,用于在Python程序中创建抽象基类。

  抽象基类可以不实现具体的方法(当然也可以实现,只不过子类如果想调用抽象基类中定义的接口需要使用super())而是将其留给派生类实现。抽象基类可以被子类直接继承,也可以将其他的类”注册“(register)到其门下当虚拟子类,虚拟子类的好处是你实现的第三方子类不需要直接继承自基类但是仍然可以声称自己子类中的方法实现了基类规定的接口(issubclass(), issubinstance())!

  虚拟子类是通过调用metaclass是 abc.ABCMeta 的抽象基类的 register 方法注册到抽象基类门下的,可以实现抽象基类中的部分API接口,也可以根本不实现,但是issubclass(), issubinstance()进行判断时仍然返回真值。

  直接继承抽象基类的子类就没有这么灵活,在metaclass是 abc.ABCMeta的抽象基类中可以声明”抽象方法“和“抽象属性”,直接继承自抽象基类的子类虽然判断issubclass()时为真,但只有完全覆写(实现)了抽象基类中的“抽象”内容后,才能被实例化,而通过注册的虚拟子类则不受此影响。

  metaclass为 abc.ABCMeta 的抽象基类如果想要声明“抽象方法”,可以使用abc模块中的装饰器 @abstractmethod ,如果想声明“抽象属性”,可以使用abc模块中的 @abstractproperty 。

  最后,为什么要提six模块呢,six模块是Python为了兼容Python 2.x 和Python 3.x提供的一个模块,该模块中有一个针对类的装饰器 @six.add_metaclass(MetaClass) 可以为两个版本的Python类方便地添加metaclass。这样我们就可以同时利用Python中的abc模块和six模块在类的定义前添加 @six.add_metaclass(abc.ABCMeta) 来优雅地声明一个抽象基础类了!

  从理论层面打通了,下面上代码,首先看一下类装饰器 @six.add_metaclass(MetaClass) 的用法,在下面的代码中,我们希望声明类 MyClass 的metaclass是类 Meta ,注意类 Meta 需要是一个metaclass。

  1. import six
  2.  
  3. @six.add_metaclass(Meta)
  4. class MyClass(object):
  5. pass

在Python 3 等价于

  1. import six
  2.  
  3. class MyClass(object, metaclass = Meta):
  4. pass

在Python 2.x (x >= 6)中等价于

  1. import six
  2.  
  3. class MyClass(object):
  4. __metaclass__ = Meta
  5. pass

或者直接用引入装饰器的目的:

  1. import six
  2.  
  3. class MyClass(object):
  4. pass
  5. MyClass = six.add_metaclass(Meta)(MyClass)

  类装饰器 @six.add_metaclass(MetaClass) 的作用是在不同版本的Python之间提供一个优雅的声明类的metaclass的手段,事实上不用它也可以,只是使用了它代码更为整洁明了。

  下面结合一个特殊的metaclass即 abc.ABCMeta 来看一段代码:

  1. import abc
  2. import six
  3.  
  4. @six.add_metaclass(abc.ABCMeta)
  5. class PluginBase(object):
  6.  
  7. @abc.abstractmethod
  8. def func_a(self,data):
  9. """
  10. an abstract method need to be implemented
  11. """
  12. @abc.abstractmethod
  13. def func_b(self,output, data):
  14. """
  15. another abstract method need to be implemented
  16. """
  17.  
  18. class RegisteredImplementation(object):
  19.  
  20. def func_c(self, data):
  21. print "Method in third-party class, "+ str(data)
  22.  
  23. class SubclassImplementation(PluginBase):
  24.  
  25. def func_a(self,data):
  26. print "Overriding func_a, "+ str(data)
  27.  
  28. def func_b(self,data):
  29. print "Overriding func_b, "+ str(data)
  30.  
  31. def func_d(self, data):
  32. print data
  33.  
  34. PluginBase.register(RegisteredImplementation)
  35.  
  36. if __name__=='__main__':
  37. for sc in PluginBase.__subclasses__():
  38. print "subclass of PluginBase: " + sc.__name__
  39. print("")
  40. print issubclass(RegisteredImplementation, PluginBase)
  41. print isinstance(RegisteredImplementation(), PluginBase)
  42. print issubclass(SubclassImplementation, PluginBase)
  43. print("")
  44. obj1 = RegisteredImplementation()
  45. obj1.func_c("It's right!")
  46. print("")
  47. obj2 = SubclassImplementation()
  48. obj2.func_a("It's right!")
  49. print ""

  上面这端代码的含义是:

  声明一个metaclass是 abc.ABCMeta 的抽象基类 PluginBase ,为其定义两个抽象方法,等待派生类的实现。接着定义了一个第三方类 RegisterdImplementation ,将其注册为类 PluginBase 的虚拟子类。再定义一个子类 SubclassImplementation 直接继承自抽象基类 PluginBase 。

  接着进行试验,运行结果如下:

  1. subclass of PluginBase: SubclassImplementation
  2.  
  3. True
  4. True
  5. True
  6.  
  7. Method in third-party class, It's right!
  8.  
  9. Overriding func_a, It's right!

  从运行的结果我们可以看出:

  虚拟子类不算做直接继承子类,因此可以不实现抽象基类 PluginBase 的任何方法;但直接继承的子类 SubclassImplementation 必须完全实现抽象基类的抽象方法才能够实例化(这里可以注释掉 26 - 30 行的代码实验)。

  同时,不论是虚拟子类还是直接继承子类,issubclass()和issubinstance()判断他们与抽象基类的关系时都返回真值。

Python装饰器、metaclass、abc模块学习笔记的更多相关文章

  1. python 装饰器和 functools 模块

    转自:http://blog.jkey.lu/2013/03/15/python-decorator-and-functools-module/ 什么是装饰器? 在 python 语言里第一次看到装饰 ...

  2. python装饰器学习详解-函数部分

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最近阅读<流畅的python>看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记. ...

  3. Python 装饰器学习心得

    最近打算重新开始记录自己的学习过程,于是就捡起被自己废弃了一年多的博客.这篇学习笔记主要是记录近来看的有关Python装饰器的东西. 0. 什么是装饰器? 本质上来说,装饰器其实就是一个特殊功能的函数 ...

  4. Python 装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...

  5. (转载)Python装饰器学习

    转载出处:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方 ...

  6. Python装饰器学习

    Python装饰器学习(九步入门)   这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- ...

  7. Python装饰器模式学习总结

    装饰器模式,重点在于装饰.装饰的核心仍旧是被装饰对象. 类比于Java编程的时候的包装模式,是同样的道理.虽然概念上稍有不同但是原理上还是比较相近的.下面我就来谈一谈我对Python的装饰器的学习的一 ...

  8. python 装饰器、递归原理、模块导入方式

    1.装饰器原理 def f1(arg): print '验证' arg() def func(): print ' #.将被调用函数封装到另外一个函数 func = f1(func) #.对原函数重新 ...

  9. Python 日期时间处理模块学习笔记

    来自:标点符的<Python 日期时间处理模块学习笔记> Python的时间处理模块在日常的使用中用的不是非常的多,但是使用的时候基本上都是要查资料,还是有些麻烦的,梳理下,便于以后方便的 ...

随机推荐

  1. CORS跨域、Cookie传递SessionID实现单点登录后的权限认证的移动端兼容性测试报告

    简述 本文仅记录如标题所述场景的测试所得,由于场景有些特殊,且并不需兼容所有浏览器,所以本文的内容对读者也许并无作用,仅为记录. 场景.与实现 需在移动端单点登录 需在移动端跨域访问我们的服务 基于历 ...

  2. 解密OpenTSDB的表存储优化【转】

    https://yq.aliyun.com/articles/54785 摘要: 本篇文章会详细讲解OpenTSDB的表结构设计,在理解它的表结构设计的同时,分析其采取该设计的深层次原因以及优缺点.它 ...

  3. 【CNN】卷积神经网络

    什么是卷积神经网络 卷积神经网络是一种特殊的.简化的深层神经网络模型,它的每个卷积层都是由多个卷积滤波器组成.它最先由lecun在LeNet[40]中提出,网络结构如下图所示.在cnn中,图像的一小部 ...

  4. IIS7 MVC 403 禁止访问:访问被拒绝

  5. Office 2010 激活 - Failed to inject memory!

    是不是用了mini-KMS_Activator这个工具去激活?是的话,把mini-KMS_Activator点出来,使用第一个按钮Install / Uninstall KM Service把它的服务 ...

  6. python 数据工程 and 开发工具Sublime

    数据工程采集.存储.清洗.分析.可视化 编程语言C++和Javapython大法Rweb:php.html.css.javascript 结合采集:python存储:python+数据库/.csv/t ...

  7. OAuth2.0 授权的工作原理

    作者:Barret李靖链接:https://www.zhihu.com/question/19781476/answer/81020455来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...

  8. 【.Net】Thread.Start()与ThreadPool.QueueUserWorkItem()的区别

    百度搜到的靠前的几篇文章,都是写了两种API的使用实例,但并没有说清两者的具体差别. 直接上stackoverflow搜才是正确的姿势.(想上谷歌,然而十/九_大|期间VPN各种被墙,就很气) 参考: ...

  9. MyEclipse10中配置开发Python所需要的PyDev 绝对靠谱 不忽悠!

    在NLP(自然语言处理)这个领域中,Python具有良好的声誉,于是也想学习一下.首先第一步就是需要在计算机上配置Python环境.由于Python自带的编辑器太简单,使用起来不顺手,于是就考虑在相对 ...

  10. 用apt爽还是apt-get爽

    debian系linux发行版的高级软件包管理工具叫apt(for Advanced Package Tool) . debian的包管理体系很立体,dpkg -> apt ->aptit ...