zoukankan      html  css  js  c++  java
  • 类的补充:元类、元类创建过程、单例、元类实现单例

    本文目录:

    一、元类

    二、通过元类来控制类的创建过程

    三、控制类的调用(实例化)

    四、单例模式

    五、元类实现单例

     

    一、元类

    元类是什么?

    本质上也是一个类,元类是用于实例化其他类,对象怎么来的是类实例化出来的,那类这个对象怎么来的呢?就是由元类实例化出来的。因为在在python中一切皆对象。

    # class Person:
    #     pass
    
    # 类也是对象 在使用上与函数对象没啥区别
    # obj = Person
    # li = [Person]
    #
    # def func(cls):
    #     print(cls)
    # func(Person)
    
    class Dog:
        def __init__(self):
            print('狗的初始化了')
        color = 'red'
    
        def talk(self):
            print('狗叫了')
    
    d1 = Dog()
    print(Dog.__dict__)
    # 查看对象是哪个类实例化出来的
    print(d1.__class__)
    print(Dog.__class__)
    print(type(d1))
    print(type(Dog))
    # 一个类必须具备的内容 """ 1.类名 2.基类 3.名称空间 """ # 通过查看__class__发现Dog对象是有type类实例化出来的 # 既然如此,是不是可以手动调用type来实例化 class_name = "Pig" bases = (object) pic_dict = {} class_body = """ def __init__(self): print("猪的初始化") color = "red" def talk(self): print("猪在叫") """ # 执行一堆字符串代码 将生产的内容放到pic_dict中 exec(class_body,{},pic_dict) print(pic_dict) # 调用type产生一个类 c = type(class_name,bases,pic_dict) print(c) print(Dog) """ 默认情况下 所有的类都是通过type这个元类实例化的 我们完全可以自己实例化 元类的作用 用于创建类的类 成为元类 """

     

    二、通过元类来控制类的创建过程

    class MyMetaclass(type):
        # 什么时候执行?  MyMetaclass 定义一个类是 系统会自动去调用元类
        def __init__(cls,class_name,bases,namespace):
            # 既然创建类时 会自动执行 该方法 那完全可以编写一些逻辑在init中 来控制类的创建
            # 首字母必须大写否则不让创建
            if not class_name.istitle():
                raise TypeError("类名首字母必须大写!")
    
            if object not in bases:
                raise TypeError("必须显式的继承object")
    
            print(cls)
            print(class_name)
            print(bases)
            print(namespace)
    # 当求解释器执行到这行diamante时  自动调用了MyMetaclass
    # class Foo(metaclass=MyMetaclass): # 等同于 Foo = MyMetaclass()
    #     attr = 123
    #     pass
    class Foo1(object,metaclass=MyMetaclass): # 等同于 Foo = MyMetaclass()
        attr = 123
        pass

     

    三、控制类的调用(实例化)

    class Bar:
        def __call__(self,*args,**kwargs):
            print("run call")
    
    # 调用类时 还是调用对象时执行
    b1 = Bar()
    
    b1()
    print(b1)
    # 在调用对象时,自动触发了__call__的执行
    # 推到b1是Bar的实例,调用b1会触发bar中的__call__
    # Bar是Type的实例,调用Bar应当触发type中的__call__
    
    class MyMetaClass(type):
    
        def __call__(self, *args, **kwargs):
            print("MyMetaClass __call__ run!")
            print(self)
    
            # 需求判断实例化时的参数必须是字符串类型
            if type(args[0])!= str:
                raise TypeError('名字必须是字符串类型!')
            # 这是自定义元类时,必须要有的模板,以保证可以正常实例化产生对象
            obj = object.__new__(self)
            obj.__init__(*args,**kwargs)
            return obj
    
    class Foo(metaclass=MyMetaClass):
        def __init__(self,name):
            self.name = name
        pass
    
    # 调用类本质上就是调用__call__ 其返回值表示实例化得到的对象
    res = Foo('bbb')
    print(res)
    # 调用一个类,创建出一个空对象,调用__init__来完成对象的初始化,返回该对象
    # 控制类的调用,也就是实例化过程,核心函数元类中的__call__
    # 需要注意的是,在__call__中应当先完成基础的逻辑1.创建空对象 2.执行__init__ 3.返回新对象
    # 在此基础上添加新的业务逻辑

     

    四、单例模式

    """
    
        单例
            是一种设计模式
            是设计模式中比较简单的
            指的是 一个类有且仅有一个实例 就叫单例
    
        实现单例 就通过判断是否已经创建过对象
    
        为什么要使用单例这种模式
        之前在创建对象时 每个对象中的数据不相同   对象实际上数据和处理数据的方法的结合体
        当对象中的数据是 相同的 共享的 时候 使用单例
    
    
        u1 = user("张三",29,"man")
        u2 = user("张三",29,"man")
        u3 = user("张三",29,"man")
        不同的对象 有完全相同的数据  没有必要每个人保存一份
    
        u1 = user("张三",29,"man")
        u2 = u1
        u3 = u1
        如此  可以减少资源开销  大家共享一个数据 只有一个对象
    
    
    """
    
    class User:
    
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        instance = None
        # 通过指定的方法来获取实例 而不是调用类来创建新对象
        @classmethod
        def get_instance(cls,name,age,sex):
            if not cls.instance:
                cls.instance = cls(name,age,sex)
            return cls.instance
    
        @staticmethod
        def get_instance2(name,age,sex):
            if not User.instance:
                User.instance = User(name,age,sex)
            return User.instance
    
    # u1 = User("张三",20,"man")
    # u2 = User("张三",20,"man")
    
    
    
    u1 = User.get_instance2("张三",20,"man")
    print(u1)
    u2 = User.get_instance2("张三",20,"man")
    print(u2)
    
    
    # 通过classMethod 可以完成单例  但是还是可以通过直接调用;类产生新对象  此时就需要用到元类
    u3 = User("张三",20,"man")

     

    五、元类实现单例

    class MyMetaClass(type):
    
        instance = None
        def __call__(cls, *args, **kwargs):
            if not MyMetaClass.instance:
                # 创建空对象
                MyMetaClass.instance = object.__new__(cls)
                print("创建新的播放器对象!")
                #初始化对象
                MyMetaClass.instance.__init__(*args,**kwargs)
                # 返回对象
            return MyMetaClass.instance
    
    # 只能有一个播放器实例
    class CDPlayer(metaclass=MyMetaClass):
        def play(self,music):
            print("切换音乐",music)
        def __init__(self,music_name):
            self.music_name = music_name
    
    p1 = CDPlayer("你发如雪!")
    p1.play("菊花台")
    p1.play("菊花台2")
    p1.play("菊花台3")
    
    # 不会创建新对象
    p1 = CDPlayer("你发如雪!")
    p1 = CDPlayer("你发如雪!")
    p1 = CDPlayer("你发如雪!")
    p1 = CDPlayer("你发如雪!")
    
    # 元类实现单例 就是拦截了元类中的__call__的正常执行  使得创建对象都必须经过自己判断逻辑
    
    
    
    
    # 类中的__init__也被拦截了

    资料参考:

    https://www.jianshu.com/p/c1ca0b9c777d(python元类)

  • 相关阅读:
    DOM
    ES6的export和import
    JavaScript:Location
    垃圾回收机制之一:标记删除算法
    KnockoutJS:
    package.json
    2016/7/27
    requirejs:研究笔记
    postmessage/cors跨域postMessage、xhr2和xmldomain
    javascript:算法之数组sort排序
  • 原文地址:https://www.cnblogs.com/wuzhengzheng/p/10273495.html
Copyright © 2011-2022 走看看