python3 元类编程的一个例子
【引子】
虽然我们可以通过“class”语句来定义“类”,但是要想更加细粒度的控制“类”的创建,要使用元类编程才能实现。
比如说我们要实现这样的一个约束、所有项目中用到的类都应该要为它定义的方法提供文档字符字符串。有两条可行
的路径 1):依赖工程师的自觉、自律 让他们在定义每一个方法的时候都为方法增加文档字符串, 2):通过元类来做一些
控制,如果工程师没有为方法提供文档字符,那么就直接报错,直到工程师为方法提供字符串为止。
【实现1】
依赖工程师的自觉、自律为方法增加文档字符串
class Person(object):
name = None
def __init__(self,name):
self.name=name def say_hello(self):
"""
print hello My name is xxx ...
"""
print("hello My name is {self.name}".format(self=self))
我们如何能保证每一个方法都增加了文档字符串呢?我一方面要依靠“自觉”另一方面要依靠“纪律性”,最好要有专门的人来做代码
审核。
【实现2】
通过元类来实现这个约束
第一步:定义一个元类来审核class
class DocMeta(type):
"""
检查方法是否有提供文档字符串
"""
def __init__(self,name,base,attrs):for key,value in attrs.items():
if key.startswith('__'):
#跳过魔术方法
continue
if not hasattr(value,"__call__"):
#跳过字段
continue
#如果能进入到这里、那么一定是方法了、于是检查方法有没有文档字符串.
if not getattr(value,"__doc__"):
#没有文档字符串的情况下就报错
raise TypeError("{0} must have a docstring".format(key))
super().__init__(name,base,attrs)
第二步:定义一个通用的基类、以后所有要实现这一约束的类都继承自它
class Documented(metaclass=DocMeta):
pass
注意这个项的元类是我们刚才定义的“DocMeta”类
第三步:让项目中的类继承自这个基类
class Person(Documented):
name = None
def __init__(self,name):
self.name=name def say_hello(self):
"""
print hello My name is xxx ...
"""
print("hello My name is {self.name}".format(self=self))
第四步:和使用普通的类一样使用Person类
if __name__=="__main__":
p = Person("welson")
p.say_hello() #hello My name is welson
【总结】
以上代码由于在say_hello 方法中提供了文档字符串、如果没有提供的话、在创建Person类的时候就会报错了
Traceback (most recent call last):
File "main.py", line 31, in <module>
class Person(Documented):
File "main.py", line 24, in __init__
raise TypeError("{0} must have a docstring".format(key))
TypeError: say_hello must have a docstring
全部代码如下:
"""
Python元类编程的一个例子
""" __version__ = '0.1'
__author__ = '蒋乐哥哥' class DocMeta(type):
"""
检查方法是否有提供文档字符串
"""
def __init__(self,name,base,attrs):
for key,value in attrs.items():
if key.startswith('__'):
#路过魔术方法
continue
if not hasattr(value,"__call__"):
#跳过字段
continue
#如果能进入到这里、那么一定是方法了、于是检查方法有没有文档字符串.
if not getattr(value,"__doc__"):
#没有文档字符串的情况下就报错
raise TypeError("{0} must have a docstring".format(key))
super().__init__(name,base,attrs) class Documented(metaclass=DocMeta):
pass class Person(Documented):
name = None
def __init__(self,name):
self.name=name def say_hello(self):
"""
print hello My name is xxx ...
"""
print("hello My name is {self.name}".format(self=self)) # 在不为方法提供文档字符串的情况下会直接报错
#class Person(Documented):
# name = None
# def __init__(self,name):
# self.name=name
#
# def say_hello(self):
# print("hello My name is {self.name}".format(self=self)) if __name__=="__main__":
p = Person("welson")
p.say_hello()
----------------------------------------
python3 元类编程的一个例子的更多相关文章
- Python 元类编程实现一个简单的 ORM
概述 什么是ORM? ORM全称"Object Relational Mapping",即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码 ...
- Python进阶开发之元类编程
系列文章 √第一章 元类编程,已完成 ; 本文目录 类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战:ORM . 类是如何产生的 类是如何产生?这个问题肯定很傻.实则不然,很多 ...
- Python元类编程
来源:http://python.jobbole.com/88582/ @property装饰器,是将类中的函数当做属性调用 Python类中定义的属性,如果属性名前面只有一个下划线,那么就是一种规范 ...
- PythonI/O进阶学习笔记_7.python动态属性,__new__和__init__和元类编程(上)
content: 上: 1.property动态属性 2.__getattr__和__setattr__的区别和在属性查找中的作用 3.属性描述符 和属性查找过程 4.__new__和__init__ ...
- python的元类编程
廖雪峰的python教程有python元类编程示例,综合代码如下 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df ...
- 元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解
__new__与__init__的理解 __new__()方法是在创建实例之前被调用的,它的作用是创建一个实例,然后返回该实例对象,它是一个静态方法. __init__() 当实例被创建完成之后被调用 ...
- 3.python元类编程
1.1.propety动态属性 在面向对象编程中,我们一般把名词性的东西映射成属性,动词性的东西映射成方法.在python中他们对应的分别是属性self.xxx和类方法.但有时我们需要的属性需要根据 ...
- gj8 元类编程
8.1 property动态属性 from datetime import date, datetime class User: def __init__(self, name, birthday): ...
- 元类编程-- metaclass
#类也是对象,type创建类的类 def create_class(name): if name == "user": class User: def __str__(self): ...
随机推荐
- 转:nginx模块开发——handler(二)
模块上下文结构 这是一个ngx_http_module_t类型的静态变量.这个变量实际上是提供一组回调函数指针,这些函数有在创建存储配置信息的对象的函数,也有在创建前和创建后会调用的函数.这些函数都将 ...
- js 判断是否是空对象
主要思路 我们要考虑到的主要有:js原生对象,宿主对象(浏览器上面的). 首先对于宿主对象 主要判断是DOM 对象 和是否是window 对象 是否是DOM对象 value.nodeType 是否存 ...
- IE浏览器兼容方案
1.使用高版本渲染模式 <meta http-equiv=”X-UA-Compatible” content=”IE=edge,chrome=1″/> 2.css hack (1)条件注释 ...
- Jquery为动态添加的未来元素绑定事件
语法: $(selector).on(event,childSelector,data,function) event:必需.规定要从被选元素移除的一个或多个事件或命名空间.由空格分隔多个事件值,也可 ...
- 关于0xFFFFFFFF和alpha,温故而知新
做图像处理都好多年了,今天随手做个小画板的时候,发现一个挺有趣的小坑.而其实这个小坑,以前也坑过自己,不过太久没处理了,又踩到坑里了. 先来看看:0xFFFFFFFF>>24 这个结果是什 ...
- 转:Ogre TerrainGroup地形赏析
1.1 参考 http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Ogre+Terrain+System http://www.ogre3d.org ...
- DLL中不能调用CoInitialize和CoInitializeEx
在项目中为了用API访问Wmi Object来实现命令wmic的功能,所以得使用COM库,使用COM库之前得初始化一些东西. m_hr = CoInitializeEx(, COINIT_APARTM ...
- javascript基础 思维导图2
来源于:http://www.cnblogs.com/xianyulaodi/p/5886128.html 1.javascript数据类型 2.javascript数组 3.javascript运算 ...
- tf.gfile
一.功能和目的 tf.gfile模块定义在tensorflow/python/platform/gfile.py,但其源代码实现主要位于tensorflow/tensorflow/python/lib ...
- webshell文件下载器
拥有webshell的服务器可以ping通主机A,这就表明webshell可以向主机A post一些数据. 在主机A上开启一个接受文件的http服务,在webshell中使用文件上传命令进行上传. 主 ...