zoukankan      html  css  js  c++  java
  • 元类

    元类介绍

    一切源自于一句话:python中一切皆为对象。既然如此类是不是也是对象呢?
    所有的对象都是实例化类得到的,类也是对象,
    那么类是怎么得到的呢?类是由于元类实例化得到的.
    创建类的流程分析
    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()
    # 仅执行一次创建播放器
  • 相关阅读:
    [洛谷P2745] [USACO5.3]窗体面积Window Area
    [洛谷P2751] [USACO4.2]工序安排Job Processing
    [洛谷P2738] [USACO4.1]篱笆回路Fence Loops
    [洛谷P4609] [FJOI2016]建筑师
    [洛谷P3228] [HNOI2013]数列
    解决Qt5使用SSL的“qt.network.ssl: QSslSocket: cannot resolve SSLv2_client_method”错误
    qt查看是否支持SSL
    qt获取依赖的openssl的版本
    qt关闭ssl验证,解决不能正常使用自签署ssl证书API的问题
    使用OpenSSL创建HTTPS所使用的SSL证书
  • 原文地址:https://www.cnblogs.com/gongcheng-/p/10029113.html
Copyright © 2011-2022 走看看