1.什么是元类
一切源自于一句话:python中一切皆为对象。既然如此类是不是也是对象呢?
class Teacher(object):
school='tsinghua'
def __init__(self,name,age):
self.name=name
self.age=age
def say(self):
print('%s says welcome to the Beijing' %self.name)
t1=OldboyTeacher('egon',18)
print(type(t1)) #查看对象t1的类是<class '__main__.OldboyTeacher'>
所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象t1是调用类Teacher得到的
一切皆对象的话 类也必然是一个对象,验证一下
tcls = Teacher
li = [Teacher]
def func(cls):
print(cls)
func(Teacher)
#完全没问题把他当做对象来使用 和其他对象没有任何区别
思考,t1是通过Teacher实例化得到的,那Teacher对象是哪个类实例化的呢?
print(type(Teacher))
#<class 'type'>
可以推导出===>产生Teacher的过程一定发生了:Teacher=type(...)
用于实例化产生类的类称之为元类 就是此时的type类;
Teacher是通过type实例化得到的,既然如此,是不是可以自己调用type来实例化一个calss呢?
2.创建类的流程分析
class关键字在帮我们创建类时,必然帮我们调用了元类Teacher=type(...),那调用type时传入的参数是什么呢?必然是类的关键组成部分,一个类有三大组成部分,分别是
1、类名class_name='Teacher'
2、基类们class_bases=(object,)
3、类的名称空间class_dic,类的名称空间是执行类体代码而得到的
调用type时会依次传入以上三个参数
自己来实例化一个类
class_name = "Teacher"
class_body = """
def __init__(self,name,age):
self.name=name
self.age=age
def say(self):
print('%s says welcome to the Beijing' %self.name)
"""
class_dict = exce(class_body)
bases = (object,)
Teacher = type(class_name,class_body,bases)
综上,class关键字帮我们创建一个类应该细分为以下四个过程
1.获取类名
2.获取基类
3.获取名称空间
4.实例化元类得到类
补充__call__
函数得执行时机
该方法会在调用对象是自动触发执行 (对象加括号)
class Foo:
def __call__(self, *args, **kwargs):
print("run")
f = Foo()
f()
自定义元类控制类的创建
一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用metaclass关键字参数为一个类指定元类
class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
pass
class Teacher(object,metaclass=Mymeta): # Teacher=Mymeta('Teacher',(object),{...})
school='tsinghua'
def __init__(self,name,age):
self.name=name
self.age=age
def say(self):
print('%s says welcome to the Beijing' %self.name)
需求
1.规范类名必须大写
2.类中必须包含文档注释
class MyMate(type):
def __init__(self,name,bases,dic):
print("run")
if not dic.get("__doc__"):
raise TypeError("类必须有文档注释!")
if not name.istitle():
raise TypeError("类名必须大写开头!")
super().__init__(name,bases,dic)
class Foo(object,metaclass=MyMate):
pass
自定义元类控制类的调用
控制类的调用过程 关键在于call函数, 类也是对象,调用类必然也会执行call函数
class MyMate(type):
def __init__(self,name,bases,dic):
print("run")
if not dic.get("__doc__"):
raise TypeError("类必须有文档注释!")
if not name.istitle():
raise TypeError("类名必须大写开头!")
super().__init__(name,bases,dic)
def __call__(self, *args, **kwargs):
# 创建空对象
# 调用init
# 返回初始化后的对象
obj = object.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj
class Foo(object,metaclass=MyMate):
"""
"""
def __init__(self):
print("初始化对象")
pass
f = Foo()
print(f)
元类实现单例
什么是单例,
单例是指的是单个实例,指一个类智能有一个实例对象
为什么要用单例
当一个类的实例中的数据不会变化时使用单例,数据是不变的
例如开发一个音乐播放器程序,音乐播放器可以封装为一个对象,那你考虑一下,当你切歌的时候,是重新创建一个播放器,还是使用已有的播放器?
因为播放器中的数据和业务逻辑都是相同的没有必要创建新的,所以最好使用单例模式,以节省资源,
#使用classmethod 实现单例
class Player():
def __init__(self):
print("创建播放器了")
__play = None
def get_player(cls):
if not cls.__play:
cls.__play = Player()
return cls.__play
p1 = Player.get_player();
p1 = Player.get_player();
p1 = Player.get_player();
p1 = Player.get_player();
该方法无法避免使用者直接调用类来实例化,这样就不是单例了
使用元类实现单例模式
#在类定义时 自动执行init 在init中创建实例 call中直接返回已有实例
class MyMeta(type):
__instance = None
def __init__(self,name,bases,dic):
if not self.__instance:
self.__instance = object.__new__(self)
self.__init__(self.__instance)
super().__init__(name, bases, dic)
def __call__(cls):
return cls.__instance
class Player(metaclass=MyMeta):
def __init__(self):
print("创建播放器了")
Player()
Player()
# 仅执行一次创建播放器