元类

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
    @classmethod
    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()
# 仅执行一次创建播放器

posted @ 2018-11-27 09:52  萤huo虫  阅读(167)  评论(0编辑  收藏  举报