• 元类,单例模式


    元类

    • t ype
    • 一个造类的对象
    • 实例化:元类-->类-->对象
    class Foo:
        pass
    
    f = Foo()
    print(f.__class__)
    print(f.__class__.__class__)
    
    <class '__main__.Foo'>
    <class 'type'>
    

    造类的第一种形式

    • 使用type模仿class关键字造类

    class做了什么事

    类的三部分

    1. 类名:class_name = Foo
    2. 类体代码:class_body开辟内存空间,把属性和方法放入一个名称空间里
    3. 父类(基类):class_bases = (object,)
    # eval方法:用来解析某一个具体的数据类型
    # eval('[1, 1]')	# [1, 1]	
    
    # exec方法:会把字符里的代码运行,并且放入名称空间
    class_body = '''
    count = 1
    '''
    
    class_name = 'Foo'
    class_bases = (object,)		# 加了逗号才是元祖
    
    class_dic = dict()
    exec(class_body, {}, class_dic)		# {}里是当前所有的内置方法
    Foo1 = type(class_name, class_bases, class_dic)
    print(Foo1)		# Foo1只是变量名,实际上的类名是由class_name定的
    print(Foo1.count)
    
    <class '__main__.Foo'>
    1
    

    控制元类产生的类

    • 在type和类的中间加一层控制

    • Foo= Mymeta(class_name, class_bases, class_dic)

    • 用super是为了调用type类里的

    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):	# 只是形参,叫什么都可以
            # 这里可以对类的属性进行操作,如:
            if class_name.islower():
                raise TypeError('类名必须大写')
                
            if not class_dic.get('__doc__'):	# ''''''的注释在字典中保存键名为__doc__
                raise TypeErroe('必须得加注释')
                
            # 方法继承自type
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            
    class Foo(metaclass=Mymeta):	# 把类名,类体代码,父类传递给Mymeta,进而产生类
        '''这种注释才有doc'''
        def __init__(self, name):
            self.name = name
            
            
    print(Foo)
    print(Foo.__class__)
    print(Foo.__dict__)
    
    <class '__main__.Foo'>
    <class '__main__.Mymeta'>	# 实例化出他的类已变成了Mymeta
    {'__module__': '__main__', '__doc__': '这种注释才有doc', '__init__': <function Foo.__init__ at 0x0000015E63D7D950>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>}
    

    控制元类产生的对象

    • 实例化类的时候会自动触发__init__方法,(实际上是触发__new__

    • 实例化对象的时候会自动触发__call__

    • 举例验证:

    class Foo():
        def __init__(self):
            print('init')
        def __call__(self, *args, **kwargs):
            print('call')
    
    f = Foo()
    f()
    
    init
    call
    
    • 控制对象产生
    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            
        def __call__(self, *args, **kwargs):
            # self就是People, args就是name和x,kwargs没传值
            print('self', self)
            print(args, kwargs)
            
            # 以下是造对象的过程
            # 造一个空类
            obj = self.__new__(self)	# 造一个空类{},固定写法
            print(1, obj.__dict__)
            
            # 造对象
            # 相当于调用People.__init__({}, 'leijun', 1)
            self.__init__(obj, *args, **kwargs)
            
            # obj就变成了{'name', 'leijun'}
            print(2, obj.__dict__)
            return obj	# 对象实例化
        
    class People(object, metaclass=Mymeta):
        def __init__(self, name, x):
            self.name = name
     
    P = People('leijun', 1)
    
    self <class '__main__.People'>
    ('leijun', 1) {}
    1 {}
    2 {'name': 'leijun'}
    

    实例化类

    • 实际上是在调用__new__

    __new__ 和 __init__

    • __init__是在初始化类
    • __new__是在构造类
    class Foo:
        def __new__(cls, *args, **kwargs): # 传类
            print(cls)
            print('new')
        	return object.__new__(cls) 		# 这里要用父类,不能用cls,不然会一直循环
        
        def __init__(self):
            print('init')
           
    f = Foo()
    print(f)
    

    加上元类后类的属性查找顺序

    • 对象本身-->类-->父类-->object-->自定义的元类->type找不到报错
    • 这里先找object是因为这个类是继承自object的,和元类是两条关系线,找完继承这一条,才会去找元类
    • 可以通过类.mro()来查看继承自哪里,只有新式类可以使用

    类中属性的查找顺序..jpg

    元类控制模版

    class Mymeta(type):
        def __init__(self, class_name, class_bases, class_dic):
            # 这里控制类的产生
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            
        def __call__(self, *args, **kwargs):
            # 这里控制实例化对象时传的参数,由于自己的类中没定义,所以会使用object中的,由于属性的查找顺序,即便在元类中定义了__new__方法,也不会被使用
            obj = self.__new__(self)	# 建空类,产生一个空对象obj
            self.__init__(obj, *args, **kwargs)	# 初始化对象obj
            
           	# 这里控制对象的产生
            return obj
    

    单例模式

    • 类用同一种方式调用多个东西时,产生的都是同一个东西
    • 目的是为了减少资源开销,当这个类的对象中的数据是共享的时候

    1. 使用类方法的特性

    NAME = 'leijun'
    
    class People():
        __instance = None	# 默认值
        
        def __init__(self, name):
        	self.name = name
        
        @classmethod
        def from_conf(cls):
            if cls.__instance:	# 如果默认值已产生就按默认值,避免二次产生导致id不同
                return cls.__instance
            
            cls.__instance = cls(NAME)	# 没产生就产生默认值
            return cls.__instance
        
    p1 = People.from_conf()
    p2 = People.from_conf()
    print(id(p1))	# 2242450203144
    print(id(p2))	# 2242450203144
    

    2.使用装饰器

    NAME = 'leijun'
    
    def deco(cls):
        cls.__instance = cls(NAME)	# 默认值
        
        def wrapper(*args, **kwargs):
            if len(args) == 0 and len(kwargs) == 0:		# 没输出就按默认值
                return cls.__instance
            
    		res = cls(*args, **kwargs)
            return res
        
        return wrapper
    
    @deco
    class People():
    def __init__(self, name):
        self.name = name 
        
    p1 = People()
    p2 = People()
    print(id(p1))	# 2458763959432
    print(id(p2))	# 2458763959432
    

    3.使用元类

    NAME = 'leijun'
    
    class Mymeta(type):
        
        def __init__(self, class_name, class_bases, class_dic):
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)
            self.__instance = self(NAME)
            
        def __call__(self, *args, **kwargs):
            if len(args) == 0 and len(kwargs) == 0:
                return self.__instance
            
            obj = self.__new__(self)	# 这是可以用self因为这个self本身没有new方法,所以也要去找父类,就不会出现循环,如果self本身有new,就用父类名,最好是用object
           	self.__init__(obj, *args, **kwargs)
            return obj
        
    class People(metaclass=Mymeta):
        def __init__(self, name):
            self.name = name
            
    p1 = People()
    p2 = People()
    print(id(p1))
    print(id(p2))
    
  • 相关阅读:
    Tiburon 支持 Unicode 的 LoadFromFile, SaveToFile
    截图:截取当前程序的界面,并保存到bmp图片中。
    List和string
    Can/CanOpen资料
    C语言的字节对齐及#pragma pack的使用
    Delphi操作Excel(2) Stringgrid导出到Excel
    zt:16进制Motorola Srecords 文件格式
    Python核心教程(第二版)读书笔记(二)
    Python核心教程(第二版)读书笔记(一)
    Python核心教程(第二版)读书笔记(三)
  • 原文地址:https://www.cnblogs.com/lucky75/p/11066829.html
Copyright © 2020-2023  润新知