笔记-python-元类metaclass
笔记-python-元类metaclass
1. 元类
1.1. 类也是对象
class Person(object):
pass
上面的代码会在内存中创建一个类,它也是对象,
- 可以将它赋值给一个变量;
- 可以拷贝它;
- 可以为它增加属性;
- 可以将它作为函数参数进行传递;
1.2. 动态地创建类
类也是对象,可以在运行时动态的创建它们,可以在函数中创建类。
>>> def chosse_class(name):
if name == 'fa':
class Fa(object):
pass
return Fa
else:
class Fb(object):
pass
return Fb
>>> myclass = chosse_class('ff')
>>> dir(myclass)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> myclass
<class '__main__.chosse_class.<locals>.Fb'>
>>> myclass()
<__main__.chosse_class.<locals>.Fb object at 0x00000092615AFD30>
使用class可以创建类,是通过python内置功能函数完成的,能不能手动创建类呢?
1.3. type
type(1) #<class 'int'>
常用来查看类型,但type还可以动态的创建类。
类的三大关键组成部分:类名,类的基类(们),类的名称空间;将这些参数传递给type就可以手动创建类了。
语法:
type(类名, 父类元组(继承,可以为空),属性字典)
下面两部分代码的功能是一样的;
>>> class Pa(object):
pass
>>> Pa
<class '__main__.Pa'>
>>> myclass = type('Pb', (), {})
>>> myclass
<class '__main__.Pb'>
1.4. 元类
元类就是类的类,是道生一的道;
简单来说,要创建实例需要先定义类;要定义类需要先创建类,创建类的根据是metaclass。
换句话说就是得先定义metaclass,再创建类,最后创建实例。
type是一个元类,type是python创建所有类的元类,类是type实例化的结果。
可以通过查看__class__属性来检查。
>>> age = 35
>>> age.__class__
<class 'int'>
>>> age.__class__.__class__
<class 'type'>
>>> foo.__class__
<class 'function'>
>>> foo.__class__.__class__
<class 'type'>
说明:
- __class__表示实例的类;
- __bases__表示父类;
总而言之,type是python的默认的元类,所有的类都是从它而来。
使用type创建类,实际上是:
Student = type()返回的一个类对象
student = Student()
2. 自定义元类
有时需要自定义元类。
定义语法:
class Foo(base1,base2,metaclass = mymeta):
也可以在类基列表中使用* args和** kwargs -style参数:
class Foo(base1, base2, metaclass=mymeta, private=True):
2.1. 元类原理及自定义元类实现
官方文档PEP3115太坑了,下面的代码很好的解释了元类原理。
引用自https://www.cnblogs.com/ManyQian/p/8882639.html
2.1.1. 步骤一
# 控制类的创建
class Mymeta(type): # 继承默认元类的一堆属性
def __init__(self, class_name, class_bases, class_dic):
if '__doc__' not in class_dic or not class_dic.get('__doc__').strip():
raise TypeError('必须为类指定文档注释')
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta, self).__init__(class_name, class_bases, class_dic)
class People(object, metaclass=Mymeta):
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
解释:People类具备了Mymeta中的校验功能。
2.1.2. 步骤二
# 控制类实例化的行为。
class People(object,metaclass=type):
def __init__(self,name,age):
self.name=name
self.age=age
def __call__(self, *args, **kwargs):
print(self,args,kwargs)
obj=People('duoduo',18)
# 对象obj是可以调用的,具体参考__call__()
obj(1,2,3,a=1,b=2,c=3)
#输出:<__main__.People object at 0x0000005BBD68E4E0> (1, 2, 3) {'a': 1, 'b': 2, 'c': 3}
#总结:如果说类People是元类type的实例,那么在元类type内肯定也有一个__call__,会在调用People('duoduo',18)时触发执行,然后返回一个初始化好了的对象obj
2.1.3. 步骤三
# 自定义元类,控制类的调用(即实例化)的过程
class Mymeta(type): #继承默认元类的一堆属性
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs):
#self=People
print(self,args,kwargs) #<class '__main__.People'> ('egon', 18) {}
#1、实例化People,产生空对象obj
obj=object.__new__(self)
#2、调用People下的函数__init__,初始化obj
self.__init__(obj,*args,**kwargs)
#3、返回初始化好了的obj
return obj
class People(object,metaclass=Mymeta):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
obj=People('duoduo',18)
print(obj.__dict__) #{'name': 'duoduo', 'age': 18}
理解:
从上面的代码我们可以看出,对象的产生其实就是,调用了类,进而触发了元类的__call__ 方法,
但是调用类产生的是对象,说明元类的__call__ 方法是用来产生对象的。
说明元类的__call__ 方法就做了下面的几件事
1、创造了一个空对象
2、调用了类的__init__ 方法
3、将参入传入__init__方法中
2.1.4. 步骤四
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
if not class_name.istitle():
raise TypeError('类名首字母必须大写')
super(Mymeta,self).__init__(class_name,class_bases,class_dic)
def __call__(self, *args, **kwargs):
#self=People
print(self,args,kwargs) #<class '__main__.People'> ('egon', 18) {}
#1、调用self,即People下的函数__new__,在该函数内完成:1、产生空对象obj 2、初始化 3、返回obj
obj=self.__new__(self,*args,**kwargs)
#2、一定记得返回obj,因为实例化People(...)取得就是__call__的返回值
return obj
class People(object,metaclass=Mymeta):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def talk(self):
print('%s is talking' %self.name)
def __new__(cls, *args, **kwargs):
obj=object.__new__(cls)
cls.__init__(obj,*args,**kwargs)
return obj
obj=People('duoduo',18)
print(obj.__dict__) #{'name': 'duoduo', 'age': 18}
2.1.5. 步骤五:案例,元类实现单例模式
#步骤五:基于元类实现单例模式
# singleton metaclass
class Singleton(type):
print('www')
def __call__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
print(cls)
cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instance
class MyClass(metaclass=Singleton):
a = 4
a1 = MyClass()
a2 = MyClass()
print(a1 == a2) #True
附录
3. type和object,class的关系
上面的内容中没有提到type和object的关系,这中间也有点绕。
先说结果,在Python的世界中,object是父子关系的顶端,所有的数据类型的父类都是它;type是类型实例关系的顶端,所有对象都是它的实例。
object是type实例化的结果,总之,一个类/函数调用后返回了一个类,这个类/函数就是元类了。如果你愿意,原理上是可以返回一个和元类相同的类的,type就是这样干的。
type(type) # <class 'type'>
更详细的信息如下:
print(type.__class__,type.__bases__)
print(object.__class__, object.__bases__)
输出:
<class 'type'> (<class 'object'>,)
<class 'type'> ()
其它内置继承于object:
>>> list.__class__
<class 'type'>
>>> list.__bases__
(<class 'object'>,)
>>> int.__class__
<class 'type'>
>>> int.__bases__
(<class 'object'>,)
比较奇特的是None,None是Python的特殊类型,NoneType对象,它只有一个值None. 但NoneType是未定义的,也没有父类。
它不支持任何运算也没有任何内建方法。
None和任何其他的数据类型比较永远返回False。
None有自己的数据类型NoneType。
你可以将None复制给任何变量,但是你不能创建其他NoneType对象。
>>>type(None)
<class 'NoneType'>
>>> None.__bases__
Traceback (most recent call last):
File "<pyshell#53>", line 1, in <module>
None.__bases__
AttributeError: 'NoneType' object has no attribute '__bases__'
>>> dir(NoneType)
Traceback (most recent call last):
File "<pyshell#51>", line 1, in <module>
dir(NoneType)
NameError: name 'NoneType' is not defined
3.1. type,object关系图
笔记-python-元类metaclass的更多相关文章
- python 元类metaclass
文章转自:http://www.cnblogs.com/linhaifeng/articles/8029564.html 一 知识储备 exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域 ...
- Python元类(metaclass)以及元类实现单例模式
这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...
- python 元类 MetaClass
type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: class Hel ...
- python 元类——metaclass
from stack overflow:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python Classes ...
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
随机推荐
- 【Android 界面效果47】RecyclerView详解
RecylerView作为 support-library发布出来,这对开发者来说绝对是个好消息.因为可以在更低的Android版本上使用这个新视图.下面我们看如何获取 RecylerView.首先打 ...
- 【Android 界面效果46】自定义view常处理的回调方法
onFinishInflate() 当View中所有的子控件均被映射成xml后触发 onMeasure(int, int) 确定所有子元素的大小 onLayout(boolean, int, int, ...
- javascript:json对象和json字符串的相互转换
json对象和字符串的相互转换 //使用json中的parser方法转换: var str='{"name":"fendouer", "age&quo ...
- April 25 2017 Week 17 Tuesday
Have you ever known the theory of chocie? There are a bunch of axiems, but there are only two thing ...
- Python-Django框架学习笔记——第一课:Hello World
Python Django 有诗云: 孤山寺北贾亭西,水面初平云脚低. 几处早莺争暖树,谁家新燕啄春泥. 乱花渐欲迷人眼,浅草才能没马蹄. 最爱湖东行不足,绿杨阴里白沙堤. 今天在信阳游玩,有幸来到信 ...
- Android(java)学习笔记70:TabActivity使用
1.首先我们要知道TabActivity是结合TabHost使用的,于是我们自然而然要说明一下TabHost 所谓的TabHost是提供选项卡(Tab页)的窗口视图容器. 此对象包含两个子对象: 一个 ...
- Codeforces 758D Ability To Convert(区间DP)
题目链接:http://codeforces.com/problemset/problem/758/D 题意:一个n进制下的数k,其中k不会用字母,如果有A就用10代替了.求k这个数对应的,在10进制 ...
- maven项目右键快捷方式,然后点击Run As
在某一个maven项目右键快捷方式,然后点击Run As就可以发现几个Maven的命令: 1.Maven Build: 这个命令用于编译Maven工程,执行命令后会在target文件夹中的classe ...
- python 合并字符串
[root@chenbj python]# cat name.py #!/usr/bin/env python # _*_ coding:utf-8 _*_ first_name = "ch ...
- C#中索引器的实现过程,是否只能根据数字进行索引?
描述一下C#中索引器的实现过程,是否只能根据数字进行索引? 答:索引器是一种特殊的类成员,它能够让对象以类似数组的方式来存取, 使程序看起来更为直观,更容易编写,可以用任意类型.