【引子】

  虽然我们可以通过“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 元类编程的一个例子的更多相关文章

  1. Python 元类编程实现一个简单的 ORM

    概述 什么是ORM? ORM全称"Object Relational Mapping",即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码 ...

  2. Python进阶开发之元类编程

    系列文章 √第一章 元类编程,已完成 ; 本文目录 类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战:ORM . 类是如何产生的 类是如何产生?这个问题肯定很傻.实则不然,很多 ...

  3. Python元类编程

    来源:http://python.jobbole.com/88582/ @property装饰器,是将类中的函数当做属性调用 Python类中定义的属性,如果属性名前面只有一个下划线,那么就是一种规范 ...

  4. PythonI/O进阶学习笔记_7.python动态属性,__new__和__init__和元类编程(上)

    content: 上: 1.property动态属性 2.__getattr__和__setattr__的区别和在属性查找中的作用 3.属性描述符 和属性查找过程 4.__new__和__init__ ...

  5. python的元类编程

    廖雪峰的python教程有python元类编程示例,综合代码如下 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df ...

  6. 元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解

    __new__与__init__的理解 __new__()方法是在创建实例之前被调用的,它的作用是创建一个实例,然后返回该实例对象,它是一个静态方法. __init__() 当实例被创建完成之后被调用 ...

  7. 3.python元类编程

     1.1.propety动态属性 在面向对象编程中,我们一般把名词性的东西映射成属性,动词性的东西映射成方法.在python中他们对应的分别是属性self.xxx和类方法.但有时我们需要的属性需要根据 ...

  8. gj8 元类编程

    8.1 property动态属性 from datetime import date, datetime class User: def __init__(self, name, birthday): ...

  9. 元类编程-- metaclass

    #类也是对象,type创建类的类 def create_class(name): if name == "user": class User: def __str__(self): ...

随机推荐

  1. Android Webservices 返回多行多列数据(Dataset)

    对于之前从事.net或者java开发人员,习惯了从后台获取网格数据(多行多列DataTable),但转行从事android开发,难免会不习惯 Android调用Webservice时,如果返回值是一个 ...

  2. 阿里DRUID数据源

    Druid是Java语言中最好的数据库连接池.Druid能够提供强大的监控和扩展功能. https://github.com/alibaba/druid/wiki/%E5%B8%B8%E8%A7%81 ...

  3. 【Linux】命令写在文件中并调用awk -f

    我们在使用awk命令的时候,有时候命令特别长,在终端写出来格式太乱,难以阅读,以下是一个将命令写在文件中,并使用awk调用的具体案例 1.现在有文件file3.txt,内容如下: 2.ak2.awk脚 ...

  4. java 增量运算符

    //java 增量运算符 public class Test16{ public static void main(String args[]) { int x1=10; x1+=3; //x1=x1 ...

  5. HDFS分布式文件系统(The Hadoop Distributed File System)

    The Hadoop Distributed File System (HDFS) is designed to store very large data sets reliably, and to ...

  6. Swift3.0 - 实现剪切板代码拷贝及跨应用粘贴

    有个需求,点击某个按钮,实现一段内容的拷贝,然后到其他应用内,直接长按粘贴. 实现如下: /// 测试剪切板,实现代码拷贝内容 func testPasteBoard(str:String) { // ...

  7. JavaScript HTML DOM 入门详解

    HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. HTML DOM 树 通过 ...

  8. Less入门与安装(转)

    快速入门 Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量.混合(mixin).函数等功能,让 CSS 更易维护.方便制作主题.扩充. Less 可以运行在 Node.浏览 ...

  9. Swift 基础知识

    前言 Swift 是一门强类型语言,全面支持 Unicode 编码. Swift 中的定义和实现是在同一个单元中的,通常一个 Swift 源代码单文件是以 .swift 结尾的. Swift 不需要单 ...

  10. c#之hello world

    前言:公司开始转型java,作为javaer,负责其他同事转型,期间以为工作需要,需要简单学习c#语法,顾有此文,及其后续的一系列文章(c#里头的一些优点,可以为提升java的思想带来帮助) 1. 安 ...