Python装饰器、metaclass、abc模块学习笔记
(博客原创作品,转载请注明出处!)
最近接触到了Python中的decorator,metaclass,abc Module,six.add_metaclass等内容,这里做一个简单的笔记。
主要资源:
1. PEP3119:Abstract Base Classes
2. abc模块:abc Module,abc—Abstract Base Classes
3. metaclass: “Python中metaclass解释”、浅析python的metaclass、PEP3115
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。
import six @six.add_metaclass(Meta)
class MyClass(object):
pass
在Python 3 等价于
import six class MyClass(object, metaclass = Meta):
pass
在Python 2.x (x >= 6)中等价于
import six class MyClass(object):
__metaclass__ = Meta
pass
或者直接用引入装饰器的目的:
import six class MyClass(object):
pass
MyClass = six.add_metaclass(Meta)(MyClass)
类装饰器 @six.add_metaclass(MetaClass) 的作用是在不同版本的Python之间提供一个优雅的声明类的metaclass的手段,事实上不用它也可以,只是使用了它代码更为整洁明了。
下面结合一个特殊的metaclass即 abc.ABCMeta 来看一段代码:
import abc
import six @six.add_metaclass(abc.ABCMeta)
class PluginBase(object): @abc.abstractmethod
def func_a(self,data):
"""
an abstract method need to be implemented
"""
@abc.abstractmethod
def func_b(self,output, data):
"""
another abstract method need to be implemented
""" class RegisteredImplementation(object): def func_c(self, data):
print "Method in third-party class, "+ str(data) class SubclassImplementation(PluginBase): def func_a(self,data):
print "Overriding func_a, "+ str(data) def func_b(self,data):
print "Overriding func_b, "+ str(data) def func_d(self, data):
print data PluginBase.register(RegisteredImplementation) if __name__=='__main__':
for sc in PluginBase.__subclasses__():
print "subclass of PluginBase: " + sc.__name__
print("")
print issubclass(RegisteredImplementation, PluginBase)
print isinstance(RegisteredImplementation(), PluginBase)
print issubclass(SubclassImplementation, PluginBase)
print("")
obj1 = RegisteredImplementation()
obj1.func_c("It's right!")
print("")
obj2 = SubclassImplementation()
obj2.func_a("It's right!")
print ""
上面这端代码的含义是:
声明一个metaclass是 abc.ABCMeta 的抽象基类 PluginBase ,为其定义两个抽象方法,等待派生类的实现。接着定义了一个第三方类 RegisterdImplementation ,将其注册为类 PluginBase 的虚拟子类。再定义一个子类 SubclassImplementation 直接继承自抽象基类 PluginBase 。
接着进行试验,运行结果如下:
subclass of PluginBase: SubclassImplementation True
True
True Method in third-party class, It's right! Overriding func_a, It's right!
从运行的结果我们可以看出:
虚拟子类不算做直接继承子类,因此可以不实现抽象基类 PluginBase 的任何方法;但直接继承的子类 SubclassImplementation 必须完全实现抽象基类的抽象方法才能够实例化(这里可以注释掉 26 - 30 行的代码实验)。
同时,不论是虚拟子类还是直接继承子类,issubclass()和issubinstance()判断他们与抽象基类的关系时都返回真值。
Python装饰器、metaclass、abc模块学习笔记的更多相关文章
- python 装饰器和 functools 模块
转自:http://blog.jkey.lu/2013/03/15/python-decorator-and-functools-module/ 什么是装饰器? 在 python 语言里第一次看到装饰 ...
- python装饰器学习详解-函数部分
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最近阅读<流畅的python>看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记. ...
- Python 装饰器学习心得
最近打算重新开始记录自己的学习过程,于是就捡起被自己废弃了一年多的博客.这篇学习笔记主要是记录近来看的有关Python装饰器的东西. 0. 什么是装饰器? 本质上来说,装饰器其实就是一个特殊功能的函数 ...
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- (转载)Python装饰器学习
转载出处:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方 ...
- Python装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- ...
- Python装饰器模式学习总结
装饰器模式,重点在于装饰.装饰的核心仍旧是被装饰对象. 类比于Java编程的时候的包装模式,是同样的道理.虽然概念上稍有不同但是原理上还是比较相近的.下面我就来谈一谈我对Python的装饰器的学习的一 ...
- python 装饰器、递归原理、模块导入方式
1.装饰器原理 def f1(arg): print '验证' arg() def func(): print ' #.将被调用函数封装到另外一个函数 func = f1(func) #.对原函数重新 ...
- Python 日期时间处理模块学习笔记
来自:标点符的<Python 日期时间处理模块学习笔记> Python的时间处理模块在日常的使用中用的不是非常的多,但是使用的时候基本上都是要查资料,还是有些麻烦的,梳理下,便于以后方便的 ...
随机推荐
- 【delphi】多线程同步之Semaphore
另外两种多线程的同步方法 CriticalSection(临界区) 和 Mutex(互斥), 这两种同步方法差不多, 只是作用域不同; CriticalSection(临界区) 类似于只有一个蹲位的公 ...
- Asp.Net正则过滤一个div
Asp.Net过滤一对标签,例如div.ul.p.li.span等 html = “html page”; Regex regPage = new Regex(@"(?is)<div\ ...
- 腾讯云主机安装登录mysql失败--解决方案[重置root密码并实现远程连接]
登录MySQL时报错:Access denied for user 'root'@'localhost' (using password: YES) 解决步骤: 1.使用ssh工具连接主机,使用mys ...
- Vue2键盘事件
这两天学习了Vue.js 感觉组件这个地方知识点挺多的,而且很重要,所以,今天添加一点小笔记,学习一下Vue键盘事件 键盘事件 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 ...
- LeetCode: Add Two Numbers 解题报告
Add Two NumbersYou are given two linked lists representing two non-negative numbers. The digits are ...
- Django import / export实现数据库导入导出
使用django-import-export库,导入导出数据,支持csv.xls.json.html等格式 官网:http://django-import-export.readthedocs.io/ ...
- 【神经网络】BP算法解决XOR异或问题MATLAB版
第一种 %% %用神经网络解决异或问题 clear clc close ms=4;%设置4个样本 a=[0 0;0 1;1 0;1 1];%设置输入向量 y=[0,1,1,0];%设置输出向量 n=2 ...
- python-minidom模块【解析xml】
1,xml的文档结构 1.1,XML文档包括XML头信息和XML信息体 1.1.1,XML文档头信息 <?xml version="1.0" encoding="u ...
- android之滑屏的实现
★理论知识 ●View在屏幕上显示出来要先经过measure(计算)和layout(布局). ◆当控件的父元素正要放置该控件时调用,父元素会问子控件“你想要用多大的地方?”,然后传入两个参数widt ...
- 为什么说Thunderbird是最好的桌面RSS阅读器
也许现在再讨论RSS阅读器似乎已经过时了,毕竟随着社交网络服务的发展,通过一个带有大众评分能力的社交网络(比如reddit),相比RSS的固定订阅而言,也许你能更快地在你所关心的话题上更快地获得新的资 ...