【引子】

  虽然我们可以通过“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. Shell 字符串分割

    入门级别 入门级别:类似1,2,3,4,5这样的字符串 #!/bin/bash var="1,2,3,4,5" var=${var//,/ } for i in $var; do ...

  2. VB.NET版+三层实现登陆

    三层已经学了一些时间了,開始认为自己能够用C#敲代码了,就用C#写了一个实现登陆的,真正再用在机房中.还是认为非常吃力的,所以.决定用vb.net敲了.以下是我用vb.net实现的登陆.能够给大家做一 ...

  3. mysql的逻辑结构

    mysql 数据库的逻辑架构如下图: 第一层,即最上一层,所包含的服务并不是MySQL所独有的技术.它们都是服务于C/S程序或者是这些程序所需要的 :连接处理,身份验证,安全性等等. 第二层值得关注. ...

  4. Python文本爬虫实战

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7019950.html  一:流程 目标:爬取目标网页的图片 1:获取网页源码 2:用Python读取源码 3: ...

  5. LeetCode118:Pascal&#39;s Triangle

    Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, Retu ...

  6. CentOS7 使用ntp设置系统时间,开机自动设置时间,

    首先如果没有安装ntp自己装一下: yum install -y ntp 然后,如果开了防火墙,记得打开自己的123端口,该端口是ntp用来同步时间的 firewall-cmd --zone=publ ...

  7. PAC Manager的重生: Asbru

    PAC Manager在2016年停更后, 在Ubuntu18.04上的各种bug就无人修复了. 我在Windows下对XShell是重度依赖, 而在Linux下没有其他更好的替代品. 在上一次安装1 ...

  8. 【jquery】ajax 动态 改变 select下拉框选中的值

    //JS<script type="text/javascript> //ajax动态给添加原料的[商品名称]下拉框绑定selected属性 $("#origin_co ...

  9. java正则表达式去除html中所有的标签和特殊HTML字符(以&开头的)

    来源于:https://www.androiddev.net/java%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8E%BB%E9%99%A4ht ...

  10. memcached缓存基本概念

    Memcached是一套分布式内存对象缓存系统. 用于在动态应用系统中缓存数据库的数据,减少数据库的访问压力,达到提升网站系统性能的目的:memcached在企业应用场景中一般是用来作为数据库的cac ...