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): ...
随机推荐
- 20个Linux防火墙[iptables]应用技巧[转]
1.显示防火墙的状态 以root权限运行下面的命令: # iptables -L -n -v 参数说明: -L:列出规则. -v:显示详细信息.此选项会显示接口名称.规则选项和TOS掩码,以及封包和字 ...
- VB控件 与 引用或部件
序号 控件名 部件或引用 用途 2 ActiveMovie Microsoft ActiveMovie Control 3 ADODB Windows ADO Ext. 2.8 for DLL ...
- React Native中常用ES6语法
一:模块导入导出 //ES6 import React, { Component, PropTypes, } from 'react'; import { Image, Text } from 're ...
- Configuring the launch of the remote virtual machine to debug
Options need to be added to the standard launch of a virtual machine (VM) to enable the debugging ar ...
- python模块之httplib(在py3中功能进一步强大,请详看文档)
# -*- coding: utf-8 -*-#python 27#xiaodeng#python模块之httplib(在py3中功能进一步强大,请详看文档) import httplib#是较为底层 ...
- UINavigationController出现nested push animation can result in corrupted navigation bar的错误提示
今天在測试过程中,出现了这样一个bug.分别有两种情景: (前提是:app是基于UINavigationController构建的) 1.从Controller-A中push进来B.在B中点击返回,返 ...
- Android拦截外拨电话
拦截监听外拨的电话,并进行处理: 向外拨打电话时系统会发出一个有序广播,虽然该广播最终会被拔号器里的广播接收者所接收并实现电话拔打,但我们可以在广播传递给拔号广播接收者之前先得到该广播,然后清除传递给 ...
- Spring 多数据源事务配置问题
2009-12-22 在SpringSide 3 中,白衣提供的预先配置好的环境非常有利于用户进行快速开发,但是同时也会为扩展带来一些困难.最直接的例子就是关于在项目中使用多个数据源的问题,似乎 很难 ...
- thunderbird中如何设置QQ邮箱
thunderbird和其他客户端设置是类似的. 我们发现您尝试设置POP3/SMTP服务,但设置未成功. 您可以检查以下的细节来解决: 您是否在邮箱中开启了这项服务,如果尚未开启,请您在[邮箱设置 ...
- 如何写UI及屏幕适配的一些技巧
总结一下关于UI布局及屏幕适配的一些实战技巧,尤其使用纯代码,会对提升效率及代码易于维护等方面有明显帮助,这里提到的没有使用任何Xib, 如果不是在外包公司,也推荐大家多使用甚至完全使用纯代码布局UI ...