说实话,我真心不太想总结这个东西,算了,炒一下egon的吧

1 引子

1 class Foo:
2 pass
3
4 f1=Foo() #f1是通过Foo类实例化的对象

python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例)

上例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?

1 #type函数可以查看类型,也可以用来查看对象的类,二者是一样的
2 print(type(f1)) # 输出:<class '__main__.Foo'> 表示,obj 对象由Foo类创建
3 print(type(Foo)) # 输出:<type 'type'>

2 什么是元类?

元类是类的类,是类的模板

元类是用来控制如何创建类的,正如类是创建对象的模板一样

元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例Foo类是 type 类的一个实例)

type是python的一个内建元类,用来直接控制生成类,python中任何class定义的类其实都是type类实例化的对象

3 创建类的两种方式

方式一:

1 class Foo:
2 def func(self):
3 print('from func')

方式二:

1 def func(self):
2 print('from func')
3 x=1
4 Foo=type('Foo',(object,),{'func':func,'x':1})

4 一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的创建,工作流程是什么)

 自定制元类
 自定制元类纯净版
 自定制元类精简版
 1 #元类总结
2 class Mymeta(type):
3 def __init__(self,name,bases,dic):
4 print('===>Mymeta.__init__')
5
6
7 def __new__(cls, *args, **kwargs):
8 print('===>Mymeta.__new__')
9 return type.__new__(cls,*args,**kwargs)
10
11 def __call__(self, *args, **kwargs):
12 print('aaa')
13 obj=self.__new__(self)
14 self.__init__(self,*args,**kwargs)
15 return obj
16
17 class Foo(object,metaclass=Mymeta):
18 def __init__(self,name):
19 self.name=name
20 def __new__(cls, *args, **kwargs):
21 return object.__new__(cls)
22
23 '''
24 需要记住一点:名字加括号的本质(即,任何name()的形式),都是先找到name的爹,然后执行:爹.__call__
25
26 而爹.__call__一般做两件事:
27 1.调用name.__new__方法并返回一个对象
28 2.进而调用name.__init__方法对儿子name进行初始化
29 '''
30
31 '''
32 class 定义Foo,并指定元类为Mymeta,这就相当于要用Mymeta创建一个新的对象Foo,于是相当于执行
33 Foo=Mymeta('foo',(...),{...})
34 因此我们可以看到,只定义class就会有如下执行效果
35 ===>Mymeta.__new__
36 ===>Mymeta.__init__
37 实际上class Foo(metaclass=Mymeta)是触发了Foo=Mymeta('Foo',(...),{...})操作,
38 遇到了名字加括号的形式,即Mymeta(...),于是就去找Mymeta的爹type,然后执行type.__call__(...)方法
39 于是触发Mymeta.__new__方法得到一个具体的对象,然后触发Mymeta.__init__方法对对象进行初始化
40 '''
41
42 '''
43 obj=Foo('egon')
44 的原理同上
45 '''
46
47 '''
48 总结:元类的难点在于执行顺序很绕,其实我们只需要记住两点就可以了
49 1.谁后面跟括号,就从谁的爹中找__call__方法执行
50 type->Mymeta->Foo->obj
51 Mymeta()触发type.__call__
52 Foo()触发Mymeta.__call__
53 obj()触发Foo.__call__
54 2.__call__内按先后顺序依次调用儿子的__new__和__init__方法
55 '''

最新文章

  1. 利用layer的mask属性实现逐渐揭示的动画效果
  2. Redis-benchmark测试Redis性能
  3. bootstrap实现弹出窗口
  4. 浏览器URL编码
  5. lua 和 c
  6. ytu 2011: C语言实验——找中间数(水题)
  7. 软件开发杂谈之从需求到上线---valen
  8. 1081. Rational Sum (20)
  9. 使用gSoap规避和修改ONVIF标准类型结构的解析
  10. 函数的上下文就是函数里面的this是谁
  11. Mybatis学习(二)常用对象SqlSessionFactory和SqlSession
  12. 提高运维效率(二)桌面显示IP
  13. CSS之使用display:inline-block来布局
  14. Object 中 equals()使用
  15. ZooKeeper Administrator&#39;s Guide A Guide to Deployment and Administration(吃别人嚼过的馍没意思,直接看官网资料)
  16. vue form表单验证
  17. 《DSP using MATLAB》Problem 7.13
  18. NodeJS对象数组Array 根据对象object key的值排序sort
  19. [Unity优化]UI优化(二):Mask组件分析
  20. 机器学习技法笔记:10 Random Forest

热门文章

  1. JavaScript本地存储实践(html5的localStorage和ie的userData)
  2. js 添加事件兼容性
  3. SPOJ IM_Intergalactic Map
  4. 【刷题】洛谷 P3573 [POI2014]RAJ-Rally
  5. 【BZOJ4247】挂饰(动态规划)
  6. 开源入侵检测系统SELKS系统搭建
  7. redis协议
  8. [SCOI2016] 背单词 (Trie树)
  9. 2.Helloworld
  10. Chapter12(动态内存)--C++Prime笔记