python基础----元类metaclass
1 引子
class Foo:
pass f1=Foo() #f1是通过Foo类实例化的对象
python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例)
上例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?
#type函数可以查看类型,也可以用来查看对象的类,二者是一样的
print(type(f1)) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建
print(type(Foo)) # 输出:<type 'type'>
2 什么是元类?
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样
元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例,Foo类是 type 类的一个实例)
type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象
3 创建类的两种方式
方式一:
class Foo:
def func(self):
print('from func')
方式二:
def func(self):
print('from func')
x=1
Foo=type('Foo',(object,),{'func':func,'x':1})
4 一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的创建,工作流程是什么)
class Mytype(type):
def __init__(self,class_name,bases=None,dict=None):
print("Mytype init--->")
print(class_name,type(class_name))
print(bases)
print(dict) def __call__(self, *args, **kwargs):
print('Mytype call---->',self,args,kwargs)
obj=self.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj class Foo(object,metaclass=Mytype):#in python3
#__metaclass__ = MyType #in python2
x=1111111111
def __init__(self,name):
self.name=name def __new__(cls, *args, **kwargs):
return super().__new__(cls)
# return object.__new__(cls) #同上 f1=Foo('name')
print(f1.__dict__) 自定制元类
自定制元类
class Mytype(type):
def __init__(self,what,bases=None,dict=None):
print('mytype init') def __call__(self, *args, **kwargs):
obj=self.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj class Foo(object,metaclass=Mytype):
x=1111111111 def __init__(self,name):
self.name=name def __new__(cls, *args, **kwargs):
return super().__new__(cls) f1=Foo('egon') print(f1.__dict__) 自定制元类纯净版
自定制元类纯净版
class Mytype(type):
def __init__(self,what,bases=None,dict=None):
print(what,bases,dict) def __call__(self, *args, **kwargs):
print('--->')
obj=object.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj
class Room(metaclass=Mytype):
def __init__(self,name):
self.name=name r1=Room('alex')
print(r1.__dict__) 自定制元类精简版
自定制元类精简版
#元类总结
class Mymeta(type):
def __init__(self,name,bases,dic):
print('===>Mymeta.__init__') def __new__(cls, *args, **kwargs):
print('===>Mymeta.__new__')
return type.__new__(cls,*args,**kwargs) def __call__(self, *args, **kwargs):
print('aaa')
obj=self.__new__(self)
self.__init__(self,*args,**kwargs)
return obj class Foo(object,metaclass=Mymeta):
def __init__(self,name):
self.name=name
def __new__(cls, *args, **kwargs):
return object.__new__(cls) '''
需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__ 而爹.__call__一般做两件事:
1.调用name.__new__方法并返回一个对象
2.进而调用name.__init__方法对儿子name进行初始化
''' '''
class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
Foo=Mymeta('foo',(...),{...})
因此我们可以看到,只定义class就会有如下执行效果
===>Mymeta.__new__
===>Mymeta.__init__
实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
''' '''
obj=Foo('egon')
的原理同上
''' '''
总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
1.谁后面跟括号,就从谁的爹中找__call__方法执行
type->Mymeta->Foo->obj
Mymeta()触发type.__call__
Foo()触发Mymeta.__call__
obj()触发Foo.__call__
2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
'''
元类总结
笔记:
class People:
def __init__(self,name):
self.name=name p=People('egon') # print(type(p))
#
# print(type(People)) #typer--->类------>对象 class Foo:
x=1
def run(self):
pass
print(type(Foo)) #type成为元类,是所有类的类,利用type模拟class关键字的创建类的过程
def run(self):
print('%s is runing' %self.name) class_name='Bar'
bases=(object,)
class_dic={
'x':1,
'run':run
} Bar=type(class_name,bases,class_dic)
print(Bar)
print(type(Bar))
元类
class Foo(metaclass=type):
x=1
def run(self):
print('running') type('Foo',(object,),{'x':1,'run':run}) class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
# print(self)
# print(class_name)
# print(class_bases)
# print(class_dic)
for key in class_dic:
if not callable(class_dic[key]):continue
if not class_dic[key].__doc__:
raise TypeError('小子,你没写注释,赶紧去写') # type.__init__(self,class_name,class_bases,class_dic)
class Foo(metaclass=Mymeta):
x=1
def run(self):
'run function'
print('running') Foo=Mymeta('Foo',(object,),{'x':1,'run':run}) print(Foo.__dict__) class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
pass
def __call__(self, *args, **kwargs):
# print(self)
obj=self.__new__(self)
self.__init__(obj,*args,**kwargs) #obj.name='egon'
return obj
class Foo(metaclass=Mymeta):
x=1
def __init__(self,name):
self.name=name #obj.name='egon'
def run(self):
'run function'
print('running')
# print(Foo.__dict__) f=Foo('egon') print(f) print(f.name)
元类的自定制
python基础----元类metaclass的更多相关文章
- 谈谈Python中元类Metaclass(二):ORM实践
什么是ORM? ORM的英文全称是“Object Relational Mapping”,即对象-关系映射,从字面上直接理解,就是把“关系”给“对象”化. 对应到数据库,我们知道关系数据库(例如Mys ...
- python中元类(metaclass)的理解
原文地址:http://www.cnblogs.com/tkqasn/p/6524879.html 一:类也是对象 类就是一组用来描述如何生成一个对象的代码. 类也是一个对象,只要你使用关键字clas ...
- 谈谈Python中元类Metaclass(一):什么是元类
简单的讲,元类创建了Python中所有的对象. 我们说Python是一种动态语言,而动态语言和静态语言最大的不同,就是函数和类不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个HelloW ...
- python 面向对象进阶之元类metaclass
一:知识储备 exec exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默认为local ...
- python 元类 MetaClass
type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: class Hel ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
随机推荐
- php 操作 oracle lob 数据
http://www.oracle.com/technetwork/articles/fuecks-lobs-095315.html Working with LOBs in Oracle and P ...
- Hive中使用sql的注意事项
一.别名的使用 定义别名:columnA as X 不需要使用单引号 使用别名:不与where同时使用 花式报错-->有说hive不支持where后使用别名 二.GROUP BY select ...
- [C++基础] 成员变量的初始化顺序
转载链接:https://blog.csdn.net/qq_37059483/article/details/78608375 1.成员变量在使用初始化列表初始化时,只与定义成员变量的顺序有关,与构造 ...
- rest_framework之渲染器
渲染器简介 什么是渲染器 根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件. 渲染器的作用 序列化.友好的展示数据 渲染器配置 首先要在settins.py中将rest_framew ...
- 如何理解IPD+CMMI+Scrum一体化研发管理解决方案之Scrum篇
如何快速响应市场的变化,如何推出更有竞争力的产品,如何在竞争中脱颖而出,是国内研发企业普遍面临的核心问题,为了解决这些问题,越来越多的企业开始重视创新与研发管理,加强研发过程的规范化,集成产品开发(I ...
- 《英文版c++语言程序设计》
compatibility [kəm,pætɪ'bɪlɪtɪ] n.兼容 compatible [kəm'pætɪb(ə)l] adj. 兼容的:能共处的:可并立的 interdependent [ɪ ...
- 阿帕奇web服务器下载部署安装运行
链接: https://jingyan.baidu.com/album/d8072ac47baf0eec95cefdca.html?picindex=4 1.apache服务安装成功可是启动失败“wi ...
- 《剑指offer》---左旋转字符串与右旋转字符串
本文算法使用python3实现 1. 问题1 1.1 题目描述: 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S, ...
- Linux的压缩/解压缩文件处理 zip & unzip
Linux的压缩/解压缩命令详解及实例 压缩服务器上当前目录的内容为xxx.zip文件 zip -r xxx.zip ./* 解压zip文件到当前目录 unzip filename.zip 另:有些服 ...
- 成功解决JSP和Servlet的中文乱码问题
表单提交时出现乱码: 在进行表单提交的时候,经常提交一些中文,自然就避免不了出现中文乱码的情况,对于表单来说有两种提交方式:get和post提交方式.所以请求的时候便有get请求和post请求.以前我 ...