一、元类
在python中一切皆对象,类实际上也是一个对象。既然类是一个对象,那它一定有一个由一个类实例化得到,这个类,就叫做元类。也就是说产生类的类,叫元类。
type是内置的一个元类,所有的类都是由type实例化得到。
在python中可以通过type()方法查看对象的类
print(type(dict))
print(type(list))
print(type(str))
print(type(object))
# 他们都是type
二、class底层原理分析
type(object_or_name, bases, dict)----> 调用type()的__init__方法
object_or_name: 类的名字,是个字符串
bases:是它的所有父类,基类
dict:名称空间,是一个字典
class底层就是调用type来实例化产生类(对象)
# 通过type来直接产生类,不用class关键字了
l = {}
exex('''
school = 'old_boy'
def __init__(self, name):
self.name = name
def score(self):
print('分数是100')
''', {}, l) # 属性和方法、全局名称空间、局部名称空间
Person = type('Person', (object,), l)
print(Person.__dict__)
print(Person.__bases__)
p = Person('nick')
print(p.name)
print(p.__dict__)
三、通过元类来控制类的产生
自定义元类:来控制类的产生,可以控制类名,可以控制类的继承父类和控制类的名称空间。
自定义元类必须继承type,写一个类继承type,这种类就叫元类
练习一:加限制,控制类名必须以sb开头
class Mymeta(type):
def __init__(self, name, bases, dic):
# 练习一:加限制 控制类名必须以sb开头
if not name.startswith('sb'):
raise Exception('类名必须以sb开头')
# metaclass = Mymeta 指定这个类生成的时候,用自己写的Mymeta这个元类
class Person(object, metaclass=Mymeta):
school = 'old_boy'
def __init__(self, name):
self.name = name
def score(self):
print('分数是100')
p = Person('nick')
# 运行程序控制台报错:'类名必须以sb开头'
练习二:类必须加注释
class Mymeta(type):
def __init__(self, name, bases, dic):
# 练习二:类中必须要有类注释
doc = self.__dict__['__doc__']
if not doc:
# 没有加注释
raise Exception('你的类没有加注释')
class Person(object, metaclass=Mymeta):
"""
我是注释
"""
school = 'oldboy'
def __init__(self, name):
self.name = name
p = Person('nick')
# 运行程序控制台不报错,因为类中有类注释
四、通过元类控制类的调用过程
控制类的调用过程,实际上就是控制对象的产生
练习:将对象中所有的属性都变成私有的
class Mymeta(type):
def __call__(self, *args, **kwargs):
# return self(*args) 会无限递归
# 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
obj = object.__new__(self)
# 调用__init__方法完成初始化
obj.__init__(*args, **kwargs)
obj.__dict__ = {f'_{self.__name__}__{k}':v for k,v in obj.__dict__.items()}
return obj
class Person(object, metaclass=Mymeta):
school = 'old_boy'
def __init__(self, name):
self.name = name
def score(self):
print('分数是100')
P = Person(name='nick')
print(p.__dict__)
print(p.name)
五、有了元类的属性查找
类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找--->去自己定义的元类中找--->type中--->报错
对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错