zoukankan      html  css  js  c++  java
  • 元类

    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()
    # 仅执行一次创建播放器
    
    
  • 相关阅读:
    U8自动、手动备份不成功 “远程组件初始化失败”
    关于延迟时间的一点智慧
    xe 最大连接数限制、记录客户连接、心跳
    应用开发框架之——根据数据表中的存储的方法名称来调用方法
    固定资产卡片管理累计折旧数不准确
    整理表索引
    用友U8固定资产总账重算语句
    新建自定义报表发布到普通菜单节点流程
    怎么更改月折旧率的小数位
    重建数据库索引等SQL常用语句
  • 原文地址:https://www.cnblogs.com/TF511/p/10024649.html
Copyright © 2011-2022 走看看