Python之元类
什么是元类?
即产生类的类就是元类,我们可以推导一下
可以先推导一下
'''
基础阶段我们使用type来查看数据的数据类型
但是现在我们学了面向对象后,发现其实本质是查看数据所属的类,而不是数据类型
'''
s = 'hello world'
l = ['hello']
d = {'name':'jack'}
i = 123
print(type(s)) # <class 'str'>
print(type(l)) # <class 'list'>
print(type(d)) # <class 'dict'>
print(type(i)) # <class 'int'>
'''
我们可以发现我们最开始学的type内置方法,查出来的时一个数据类的数据名
所以我们可以确定type方法是用来看产生对象的类名
'''
class Myclass():
pass
obj = Myclass()
print(type(obj)) # <class '__main__.Myclass'>
'''确定type方法可以看产生对象的类名,那么可以查看类名会显示什么'''
print(type(Myclass)) # <class 'type'>
'''可以得出结论,我们定义的类其实都是由type类产生的:>>>元类(产生类的类)'''
产生类的两种方式
1.使用关键字class
'1.使用关键字class'
class Student():
country = 'China'
def func(self):
pass
print(Student) # <class '__main__.Student'>
print(Student.__dict__)
2.利用元类type
'2.利用元类type'
'''
可以通过追代码的方式找到
type(object_or_name, bases, dict)
type('类名','父类'(没有可以直接写小括号),'类的名称空间'(字典的形式))
'''
# type(类名,类的父类(没有可以直接小括号),类的名称空间)
cls = type('Myclass', (), {'name': 'jack'})
print(cls) # <class '__main__.Myclass'>
c1 = cls()
print(c1) # <__main__.Myclass object at 0x0000028BA9696B50>
'''
为什么要学元类?有什么用?
学习元类其实就是掌握了类的产生过程
我们就可以在类的产生过程中高度定制化类的行为
'''
元类定制类的产生行为
思考:我们的定制化代码应该写在哪里?
推导:
对象是如何产生的?调用类然后执行类里面的__init__方法
类是如何产生的?推导应该是,创造类的类里面的__init__方法而这个类恰好是type元类
得出结论:如果想定制化类的代码,一个写在元类的__init__方法
'''
推导:使用已知推导未知
# 你能够直接修改元类的代码吗?不能够直接修改元类的源码,我们是不是可以写一个子类,
来继承type类,然后在子类里面的__init__犯法中书写定制化代码,所以还需要再子类里面
执行父类的__init__方法
'''
'''定制一个所有的类必须首字母大写 否则无法产生的功能'''
# 分析:想要干预一个类的产生,必须要考虑使用元类,元类产生类
'''步骤1:自定义元类,继承type的类也称为元类'''
class MyClass(type):
'''3.类名加括号会触发__init__初始化方法'''
'''
类中的__init__方法用于实例化对象
元类中的__init__方法用于实例化类
'''
def __init__(self, cls_name, cls_bases, cls_dict):
# 通过查看元类源码里的__init__(self,what,bases=None,dict=None)
# print(cls_name) # Zero 类名
# print(cls_bases) # () 父类
# print(cls_dict) # 名称空间(一个大字典)
# 定义一个类名首字母没大写无法产生的功能
if not cls_name.istitle():
raise Exception('类名首字母一定要大写啊!SB')
super().__init__(cls_name,cls_bases,cls_dict)
'''2.定义一个子类来继承,元类不能直接继承,需要指定metaclass= MyClass'''
# 先来一个首字母大写的看看
class Zero(metaclass=MyClass):
def __init__(self):
print('from Zero')
Zero()
print(Zero.__dict__) # 已经实现了,定制化,该类产生了
# 在来定义一个首字母不大写的类看看效果
class ankn(metaclass=MyClass):
def __init__(self):
print('from ankn')
ankn()
print(ankn.__dict__) # 已经实现了,定制化,该类没有产生
元类进阶用法
'''
元类的__call__方法
对象()的时候会调用产生对象的类中得的__call__方法
推导:
类名()?
会执行 产生类的类中得__call__方法,其实就是元类type中的__call__
'''
'''
元类不单单可以控制类的产生过程,其实也可以控制对象的
对象加括号执行产生该对象类里面的__call__
类加括号执行产生改类的元类里面的__call__
'''
'''我们可以做一个实例化对象后,让所有的参数必须都采用关键字参数的形式'''
class MyClass(type):
def __call__(self, *args, **kwargs):
'''
1.产生一个空对象(骨架)
2.调用__init__给对象天津爱独有的数据(血肉)
3.返回创建好的对象
:param args:
:param kwargs:
:return:
'''
print('__call__')
print(args) # ('jack', 18)
print(kwargs) # {}
if not kwargs:
raise Exception('喂喂!给我传关键字形参啊!')
# 返回创建好的值
return super().__call__(*args, **kwargs)
class Zero(metaclass=MyClass):
def __init__(self, name, age):
self.name = name
self.age = age
print('__init__')
# z = Zero('jack',18)
'''
观察一下Zero类里面的__init__方法和MyClass里面的__call方法执行顺序
从代码运行中可以得出结论:在执行类的__init__方法之前,其实已经执行了元类的__call__方法。
既然这样那么我们就可以在实例化对象之前做一些定制化
'''
# 实例化对象会立马触发元类里面的__call__,括号内的值是先给*args,**kwags的
z1 = Zero(name='tom',age=19)
'''
如果我们想要定制对象的产生过程可以操作元类里面的__call__
如果我们想要定类的产生过程可以操作元类里面的__init__
'''
本文介绍了Python中的元类,它是生成类的类,用于定制类的产生过程。元类的`__init__`和`__call__`方法展示了如何在类的创建和实例化阶段进行定制。通过学习元类,可以实现对类和对象行为的高级控制。
1万+

被折叠的 条评论
为什么被折叠?



