什么是元类
所有的对象都是调用类(实例化)而得来的,调用类的过程叫做类的实例化。
如果一切皆对象,那么类也是一个对象!既然对象都是通过调用类得到的,那么,调用类A得到了一个对象类B,那么类A就是元类!牛逼!
class A:
pass
a = A() #调用A得到一个对象a
'''
根据一切皆对象,类A也是一个对象,那么类A从哪来?
A = 某个类() 某个类的实例化为A
那么这个某个类,就叫元类!
'''
print(type(a)) # <class '__main__.A'>
print(type(A)) # <class 'type'>
print(type(type)) # <class 'type'> 元类type的元类为元类type
#打印对象A的类,得出:A的元类为 type 类
元类type——>实例化——>类A——>实例化——>对象a
一个类有三大组成部分:
- 类名 class_name :A
- 基类们 class_bases :(object, ) 父类们
- 类的名称空间 class_dict :执行类体代码得到的
class 这个关键字帮我们做了什么?
- 拿到类名 class_name = A
- 拿到类的基类 class_bases = (object, )
- 执行类体代码,拿到类的名称空间 class_dict = {….}
- 调用元类得到类 type(class_name, class_bases, class_dict)
创建类的三要素:类名,基类,类的名称空间
用type创建类:type(class_name, class_bases, class_dict)
自定义元类
class MyType(type): #自定义元类,继承type的类
def __init__(self, class_name, class_bases, class_dict): #类的三要素:类名,基类,名称空间
super(MyType, self).__init__(class_name, class_bases, class_dict)
print('self:', self) #self: <class '__main__.People'>
print(class_name) # People
print(class_bases) # (<class 'object'>,)
print(class_dict) #{'__module__': '__main__', '__qualname__': 'People', '__init__': <function People.__init__ at 0x10c29fb00>, 'fun': <function People.fun at 0x10c358320>}
class People(object, metaclass=MyType): #等同于:People = type('People', class_bases, class_dict)
def __init__(self, name, age):
self.name = name
self.age = age
def fun(self):
print('我是一个函数')
# 类在定义的时候就执行了,所以People不用实例化,就能得出自定义元类中的结果
元类的应用:
元类中可以自定义类的产生过程。类的产生过程其实就是元类的调用过程
# 例:实现创建类时必须有注释,类名必须大写,否则创建类会报错。
class MyType(type):
def __init__(self, class_name, class_bases, class_dict):
super(MyType, self).__init__(class_name, class_bases, class_dict)
if not class_name.istitle():
raise TypeError('类名首字母需要大写')
if not class_dict.get('__doc__') or not len(class_dict.get('__doc__').strip()):
raise TypeError('类中必须要有注释,养成一个好习惯好吗弟弟?')
class People(object, metaclass=MyType):
def __init__(self, name, age):
self.name = name
self.age = age
def fun(self):
print('老子是个函数')
__ call __
要想让类的对象变成可调用的,必须要实现 __ call __ 方法。
class TestCall:
def __call__(self, *args, **kwargs):
print('args:',args)
print('kwargs:',kwargs)
t = TestCall()
t(1,x=2)
# args: (1,)
# kwargs: {'x': 2}
#说明,类也是一个对象,所以在类的类中,也就是元类中肯定也实现了 __call__ 方法
分析一波类的调用:
类() 表示类的调用,要想让 类后面加个() 能用,这时候需要把类当做一个对象,这个对象的类中必然实现了 __ call __,我们知道,类的类时元类,所以元类中肯定实现了call方法,然后这个call返回了一个对象,元类的对象是类,类的对象就是 元类中 call 返回的对象。
__ new __:
我们知道,类在实例化的时候,会第一个调用执行类里面 __ init __ 里面的代码。但是!转折来了,类在实例化的时候,第一个调用的并不是 __ init __ 的方法,而是 __ new __,这个方法会返回一个空对象,然后再调用 init 初始化,将类实例化时后面跟的参数添加进 这个空对象 的名称空间中。
__ new __ 后面跟的参数跟 __ init __ 一样。
__ init __ 是在类实例(对象)创建之后调用的,而 __ new __ 这个方法,正是产生类实例(对象)的方法
注意:__ new __ 只能用于新式类(从object继承的类)
class People():
def __new__(cls, *args, **kwargs):
print('new_args', args) # ('egon', 19) 这个是类实例化的时候后面跟的参数
print('new_kwargs', kwargs)
return cls.__new__(cls) #自己找自己的 __ new __,会无限循环。
def __init__(self, name, age):
print('name', name)
print('age', age)
p = People('egon', 19)
#说明:这个类实例化时,第一步会先调用 __ new __ 方法 ,生成一个空对象,在People类中有一个 new ,这时候创建空对象时,会一直调用自己的 __ new __ 方法,陷入无限循环中。
利用元类自定义类的实例化
自定义类的实例化过程,本质上就是重写元类的 __ call __ 方法。因为类实例化,就是在调用元类。
class MyType(type):
def __call__(self, *args, **kwargs):
print('self:', self) # self: <class '__main__.People'>
print('**args:', args) # **args: ('KbMan', 12)
print('**kwargs:', kwargs) # **kwargs: {}
obj = self.__new__(self) # 1、先创建一个空对象,这个self是类 People
self.__init__(obj, *args, **kwargs) # 2、初始化空对象的属性
return obj # 3、返回初始化之后的对象
class People(object, metaclass=MyType):
def __init__(self, name, age):
self.name = name
self.age = age
p = People('KbMan', 12) # 类实例化时,因为类的实例化就是调用元类的过程,所以会调用元类的 __call__方法
print(p.__dict__) # {'name': 'KbMan', 'age': 12}
类的调用即类的实例化,就是元类的调用过程,可以通过自定义元类 MyType 的 __ call __ 控制调用过程。
类实例化分析:
1、类实例化实际上就是调用元类的过程,就是调用元类中 __ call __ 方法的过程
2、利用 __ new __ 生成一个People的空对象
3、为该对象调用 __ init __ 初始化属性值
4、返回该对象
自定义元类后的继承顺序
class MyType(type):
s = 'MyType元类'
class B:
# s = 'B类'
def __init__(self):
super().__init__()
class A(B):
# s = 'A类'
def __init__(self):
super().__init__()
class People(A, metaclass=MyType):
# s = 'People类'
def __init__(self):
super().__init__()
print(People.s) # 查找顺序为 People类 ——> A类 ——> B类 ——> MyType类
查找顺序:
- 先对象层:People->A->B->object
- 然后元类层:MyType->type
自定义元类后 __ new __ 的查找顺序
class MyType(type):
s = 'MyType元类'
def __call__(self, *args, **kwargs):
obj = self.__new__(self)
print(self.__new__ is object.__new__)
class B:
# s = 'B类'
def __init__(self):
super().__init__()
# def __new__(cls, *args, **kwargs):
# print('B类的__new__')
class A(B):
# s = 'A类'
def __init__(self):
super().__init__()
# def __new__(cls, *args, **kwargs):
# print('A类的__new__')
class People(A, metaclass=MyType):
# s = 'People类'
def __init__(self):
super().__init__()
# def __new__(cls, *args, **kwargs):
# print('People的__new__')
People() # __new__ 的 查找顺序为 People类 ——> A类 ——> B类 ——>object#
#注意:object类中自带 __new__,所以查到object类 肯定会结束
利用元类修改类的属性为私有属性(隐藏属性)
# 要修改的属性为类实例化出的对象的属性。
class MyType(type):
def __init__(self, class_name, class_bases, class_dict):
super().__init__(class_name, class_bases, class_dict)
# 在类实例化时修改对象属性为隐藏属性
def __call__(self, *args, **kwargs):
# 1、创建一个空对象
obj = self.__new__(self)
# 2、调用 __init__ 初始化对象属性
self.__init__(obj, *args, **kwargs)
# 3、修改对象的__dict__
obj.__dict__ = { '_{0}__{1}'.format(self.__name__, k) : v for k, v in obj.__dict__.items()}
return obj
class People(object, metaclass=MyType):
def __init__(self, name, age):
self.name = name
self.age = age
p = People('KbMan',123)
print(p.__dict__) # {'_People__name': 'KbMan', '_People__age': 123}