python metaclass 入门简介
http://cizixs.com/2015/08/30/metaclass-in-python
动态类型也是类型
python 是一种动态类型语言,换句话说每个变量可以在程序里任何地方改变它的类型。想要获取变量的类型信息,可以使用 type
:
>>> a = 2
>>> type(a)
int
>>> a = '1'
>>> type(a)
str
>>> type(str)
type
>>> type(type)
type
>>> class Test1 (object):
pass
>>> class Test2 (Test1):
pass
>>> a = Test1()
>>> b = Test2()
>>> type(a) is Test1
True
>>> type(b) is Test2
True
从上面的例子可以得到下面的结论:
- 每个变量都有自己的类型
- 变量的类型是可以随时改变的
type
只会返回对象的直接type
,就是定义该对象的类- 类的
type
还是type
,这说明 type 定义了 python 中所有类的某些基本属性
type 的第二种用法
上面提到了 type
的一种用法,查看 python 对象的类型。type
的另外一个用法就比较独特:生成类。
Help on class type in module __builtin__:
class type(object)
| type(object) -> the object's type
| type(name, bases, dict) -> a new type
来我们看一下 type 到底怎么用! 一般情况下,类的定义式这样的:
class Foo(object):
"""A class that does nothing."""
def __init__(self):
self.a = 1
def magic(self):
return self.a
使用 type
也可以做到同样的效果:
def __init__(self):
self.a = 1
def magic(self):
return self.a
Foo = type('Foo', (object,), {"__doc__": "A class that does nothing.", "__init__": __init__, "magic": magic})
foo = Foo()
print foo
print foo.a # 1
print foo.magic # <bound method Foo.magic of <__main__.Foo object at 0x100fa5d50>>
print foo.magic() # 1
type
的三个参数分别是:
- name: 要生产的类名
- bases:包含所有基类的 tuple
- dict:类的所有属性,是键值对的字典
现在再回顾一下 “python 中一切皆对象”这句话,可能会更容易理解。
metaclass 就是类的类
我们在前面看到怎么使用 type
来动态创建类,其实在 python 内部也进行着同样的步骤。这就是 metaclass 的概念!
想弄明白 metaclass,我们要搞清楚 class。因为类似于 class 定义了 instance 的行为,metaclass 则定义了 class 的行为。可以说,class 是 metaclass 的 instance。
instance 创建的时候会调用 __init__
函数,类似的,class 创建的时候会调用 __new__
函数。通过自定义 __new__
函数,你可以在创建类的时候做些额外的事情:把这个类注册到某个地方作为记录或者后续的查询,给类注入一些属性,或者干脆替换成另外一个类。
当遇到类定义的时候,
class MyClass(object):
pass
不会立即去创建这个类,而是把这段代码当做正常的 code block 来执行,结果就是生成一个命名空间(namespace),就是包含了要生成类(class-to-be)所有属性的字典,然后才会调用 __new__
函数,把类名、类的父类、类的属性传递过去,生成这个类。
看到没有,上面一段话是不是很熟悉,没错,和我们使用 type
来创建类是一样的。
总结一下:metaclass 的功能是什么?根据类的信息,来创建这个类。没错,type
就是 python 自带的 metaclass。
创建自己的 metaclass
既然可以使用 type
来创建 python 标准的类,自然而然地,继承 type
这个类,覆盖已有的内置函数,就可以创建自己的 metaclsss。
下面的内容都会基于一个这样的并metaclass:它为要创建的类自动添加一个属性__cizixs
。这个 metalcss 没有任何实际的意义,但可以帮助理解 metaclss 。
根据上面的思路,我们可以写出这样的代码:
class MyMetaclass(type):
def __init__(cls, name, bases, attrs):
cls.__cizixs = "Don't panic"
print("In MyMetaclass for {}".format(name))
super(MyMetaClass, cls).__init__(name, bases, attrs)
其实还可以覆写 __new__
函数来达到相同的目的:
class MyMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['__cizixs'] = "Don't panic"
print("In MyMetaclass for {}".format(name))
return super(MyMetaclss, cls).__new__(cls, name, bases, attrs)
class Foo(object):
__metaclass__ = MyMetaclass
pass
# In MyMetaclass for Foo
foo = Foo()
print foo.__cizixs # Don't panic
关于 __new__
和 __init__
的不同,就不在此讲述,感兴趣可以自行搜索。只想提一句,__new__
创建类,__init__
初始化类。所以 __new__
会在 __init__
之前被调用,而且 __new__
必须要返回新创建的类,__init__
不需要。
上面这段代码需要说明的几点:
__new__
函数就是类创建的时候可以使用的- 注意
__new__
是一个 classmethod,代码中参数cls
在这里就是<class '__main__.MyMetaclass'>
。 - 只要在类的定义里指定
__metaclss__
,那么这个类在创建的时候就会自动使用自定义的 metaclass,而不是系统默认的type
。 - 在创建类的时候,python 会按照这样的顺序去找要使用的 metaclass:
- 类定义时候的类变量
__metaclass__
- 类所在
MODULE
(就是当前文件)里的__metaclss__
变量 - 第一个父类定义的
__metaclas__
变量 - 系统默认的
type
metaclass
- 类定义时候的类变量
如果要控制类实例化 instance 的行为,还可以覆写 __call__
函数。
python metaclass 入门简介的更多相关文章
- Python之入门篇1
一.安装python解释器 官网: https://www.python.org/downloads/windows/ 自行下载安装,添加环境变量 #测试安装是否成功 windows --> 运 ...
- python从入门到大神---Python的jieba模块简介
python从入门到大神---Python的jieba模块简介 一.总结 一句话总结: jieba包是分词技术,也就是将一句话分成多个词,有多种分词模型可选 1.分词模块包一般有哪些分词模式(比如py ...
- Python生态环境简介[转]
Python生态环境简介 作者: Mir Nazim 原文: Python Ecosystem - An Introduction 译者: dccrazyboy 原译: Python生态环境简介 当 ...
- MongoDB入门简介
MongoDB入门简介 http://blog.csdn.net/lolinzhang/article/details/4353699 有关于MongoDB的资料现在较少,且大多为英文网站,以上内容大 ...
- Python基础入门教程
Python基础入门教程 Python基础教程 Python 简介 Python环境搭建 Python 基础语法 Python 变量类型 Python 运算符 Python 条件语句 Python 循 ...
- Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
1. Python爬虫入门教程 爬取背景 2019年1月10日深夜,打开了百思不得姐APP,想了一下是否可以爬呢?不自觉的安装到了夜神模拟器里面.这个APP还是比较有名和有意思的. 下面是百思不得姐的 ...
- (转)python生态环境简介
Python生态环境简介 作者: Mir Nazim 原文: Python Ecosystem - An Introduction 译者: dccrazyboy 原译: Python生态环境简介 当 ...
- Django笔记 —— 入门简介
最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过.Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧- 本篇笔记(其 ...
- [转帖]Flink(一)Flink的入门简介
Flink(一)Flink的入门简介 https://www.cnblogs.com/frankdeng/p/9400622.html 一. Flink的引入 这几年大数据的飞速发展,出现了很多热门的 ...
随机推荐
- P1001 第K极值【tyvj】
/*========================================== P1001 第K极值 内存限制 128MB 代码限制 64KB 描述 Description 给定一个长度为N ...
- Restfull API 示例
什么是Restfull API Restfull API 从字面就可以知道,他是rest式的接口,所以就要先了解什么是rest rest 不是一个技术,也不是一个协议 rest 指的是一组架构约束条件 ...
- Knockout应用开发指南(完整版) 目录索引
http://learn.knockoutjs.com/ 所有示例和代码都在在上面直接运行预览 注意:因为它用了google的cdn加速,所要要用代_理+_翻_墙才能正常加载 使用Knockout有 ...
- String 深浅拷贝的测试---有待继续测试
public class TestString { void test1() { // TODO Auto-generated method stub String str = new String( ...
- MYSQL 分组排名
今天遇到一个MYSQL排序的问题,要求按某列进行分组,组内进行排序. 百度一下发现MYSQL不支持row_number(),rank()等函数. 采用的办法如下,我们首先创建一个测试表: --创建表 ...
- 响应式布局设置--@media only screen and
@media only screen and only(限定某种设备) screen 是媒体类型里的一种 and 被称为关键字,其他关键字还包括 not(排除某种设备) /* 常用类型 */类型 解 ...
- SQLite介绍、学习笔记、性能测试
SQLite介绍.学习笔记.性能测试 哪些人,哪些公司或软件在用SQLite: Nokia's Symbian,Mozilla,Abobe,Google,阿里旺旺,飞信,Chrome,FireFox可 ...
- 网页颜色RGB记法和16进制记法转化方法
A=>10,B=>11,C=>12,D=>13,E=>14,F=>15 看一个例子: 254,112,85 255/16 等于 15 余 14 那么它对应的应该是F ...
- c/c++多线程编程中最好不要加volatile
来自https://www.zhihu.com/question/31459750 答主解释说:不能指望volatile能解决多线程竞争问题,除非所用的环境系统不可靠才会为了保险加上volatile, ...
- Mongodb集群搭建及spring和java连接配置记录
一.基本环境: mongdb3.0.5数据库 spring-data-mongodb-1.7.2.jar mongo-java-driver-3.0.2.jar linux-redhat6.3 tom ...