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()
    # 仅执行一次创建播放器
    
    
  • 相关阅读:
    Max Sum Plus Plus HDU
    Monkey and Banana HDU
    Ignatius and the Princess IV HDU
    Extended Traffic LightOJ
    Tram POJ
    Common Subsequence HDU
    最大连续子序列 HDU
    Max Sum HDU
    畅通工程再续
    River Hopscotch POJ
  • 原文地址:https://www.cnblogs.com/TF511/p/10024649.html
Copyright © 2011-2022 走看看