元类
python中一切皆对象,类实际上也是一个个对象,对象就一定是由一个类实例化得到的,那么这个类,就叫做元类。即,产生类的类,叫做元类。
在python中,type是内置的元类,所有的类都是由type实例化得到的。
class Student:
pass
print(type(Student))
print(type(dict))
print(type(object))
print(type(type))
# <class 'type'>
# <class 'type'>
# <class 'type'>
# <class 'type'>
class关键字底层实现原理
class 类名:会构造出一个类,实际上是元类实例化产生类这个对象
类实例化产生对象是:类名()
比如Student类是由type元类实例化产生,传一堆参数
type()会调用类的__init__
方法
type(object_or_name, bases, dict)有三个参数
object_or_name:类的名字,是个字符串
bases:是它的所有父类
dict:名称空间,一个字典
通过type可以直接产生类,不适用class关键字
所以:class底层就是调用type来实例化产生类(对象)
补充:exce方法:三个参数
第一个参数:包含一系列python代码的字符串
第二个参数:全局作用域(字典形式),如果不指定,默认为globals()
第三个参数:局部作用域(字典形式),如果不指定,默认为locals()
可以把exce命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
通过自定义元类控制类的产生
自定义元类:来控制类的产生,可以控制类名,可以控制类的继承父类,控制类的名称空间
自定义元类必须继承type,写一个类继承type,那这个类就叫元类
metaclass=Mymeta,指定一个类生成的时候,用自己写的Mymeta这个元类
class Mymeta(type):
pass
class Student(object, metaclass=Mymeta):
school = 'oldboy'
def __init__(self, name):
self.name = name
def score(self):
print('100分')
通过自定义元类控制类的调用过程
调用一个对象,就是触发对象所在类中的__call__
方法的执行。
class Mymeta(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self)
obj.__init__(*args, **kwargs)
return obj
class Student(object, metaclass=Mymeta):
school = 'oldboy'
def __init__(self, name ,age):
self.name = name
self.age = age
s1 = Student('wu', 18)
print(s1)
print(s1.__dict__)
# <__main__.Student object at 0x000001AFE0B9EA88>
# {'name': 'wu', 'age': 18}
在调用s1 = Student('wu', 18)
会做三件事:
- 调用
__call__
方法产生一个空对象obj - 调用
__init__
方法初始化对象obj - 返回初始化好的obj
有了元类之后的属性查找顺序
类的属性查找顺序:先从类本身中找-->按mro继承关系去父类中找-->去自己定义的元类中找-->type中找-->报错
对象的属性查找顺序:先从对象本身中找-->再去类中找-->按mro继承关系去父类中找-->报错