zoukankan      html  css  js  c++  java
  • 元类 单例

    # 什么是元类:
    #     源自于一句话:在python中,一切节对象,而对象都是由类实例化得到的
    # class OldBoyTeacher:
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def score(self):
    #         print('%s is scoring'%self.name)
    #
    # tea1=OldBoyTeacher('egon',18,'male')
    # print(type(tea1))    # <class '__main__.OldBoyTeacher'>
    # print(type(OldBoyTeacher))  # <class 'type'>
    # 对象tea1是调用OldBoyTeacher类得到的,如果说一切皆对象,那么OldBoyTeacher也是一个对象,只要是对象
    # 都是调用一个类实例化得到的,即OldBoyTeacher=元类(....),内置的元类是type
    
    """
    关系:
    1调用元类————》自定义的类
    2 调用自定义的类————》自定义的对象
    #
    class 关键字创建自定义类的底层的工作原理,分四步
    1 先拿到类名:OldBoyTeacher
    2 在拿到类的基类们:(object,)
    3 然后拿到类的名称空间:
        (执行类体代码,将产生的名字,放到类的名称空间也就是一个字典里,补充exec)
    4 调用元类实例化得到的自定义的类:OldBoyTeacher=type('OldBoyTeacher',(object,),{....})
    """
    
    # class OldBoyTeacher: #OldBoyTeacher=type(...)
    #     school='oldboy'
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def score(self):
    #         print('%s is scoring' % self.name)
    
    # print(OldBoyTeacher)  #<class '__main__.OldBoyTeacher'>
    # 自定义类的三个关键组成部分:
    # 1 类名
    # 2 类的基类们
    # 3 类的名称空间
    
    # 不依赖class关键字创建一个自定义类
    # 1 拿到类名
    # class_name='OldBoyTeacher'
    
    # 2 拿到类的基类们:(object,)
    # class_base=(object,)
    
    # 3 拿到类的名称空间
    # class_dic={}
    
    # class_body='''
    # school = 'Oldboy'
    #
    # def __init__(self,name,age,sex):
    #     self.name=name
    #     self.age=age
    #     self.sex=sex
    #
    # def score(self):
    #     print('%s is scoring' %self.name)
    # '''
    #      #字符串  全局名称空间  局部名称空间
    # exec(class_body,{},class_dic)
    #                     #循环字符串里面的内容变成字典形式的添加到局部名称空间中
    # print(class_dic)
    # # {'school': 'Oldboy', '__init__': <function __init__ at 0x00000000004FC268>, 'score': <function score at 0x00000000027C97B8>}
    #
    # # 4 调用type得到自定义的类
    # OldBoyTeacher=type(class_name,class_base,class_dic)
    # print(OldBoyTeacher) #<class '__main__.OldBoyTeacher'>
    # print(OldBoyTeacher.school) # Oldboy
    # print(OldBoyTeacher.score) #<function score at 0x0000000001E59840>
    #
    # tea1=OldBoyTeacher('egon',18,'male')
    # print(tea1.__dict__)
    # # {'name': 'egon', 'age': 18, 'sex': 'male'}
    
    '''
     模板
    
    class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就只是一个普通的类
        def __init__(self,class_name,class_bases,class_dic):
            print(self) #<class '__main__.OldboyTeacher'>
    
            print(class_name) #OldboyTeacher
    
            print(class_bases) #(<class 'object'>,)
    
            print(class_dic) #{'__module__': '__main__', '__qualname__': 'OldboyTeacher', 'school': 'Oldboy', '__init__': <function OldboyTeacher.__init__ at 0x00000000021B9730>, 'score': <function OldboyTeacher.score at 0x00000000021B97B8>}
    
    class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
        school = 'Oldboy'
    
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def score(self):
            print('%s is scoring' %self.name)
    '''
    """
    # 控制类的产生
    # 1 类名必须用驼峰体
    # 2 类体必须有文档注释,且文档注释不能为空
    
    class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就只是一个普通的类
        def __init__(self,class_name,class_bases,class_dic):
           if class_name.islower():
               raise TypeError('类名必须使用驼峰体')
    
           doc=class_dic.get('__doc__')
           if doc is None or len(doc)==0 or len(doc.strip('
     '))==0:
               raise TypeError('类体必须有文档注释,且文档注释不能为空')
           #  pass
    
    class OldboyTeacher(object,metaclass=Mymeta): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
        school = 'Oldboy'
    
        def __init__(self,name,age,sex):
            self.name=name
            self.age=age
            self.sex=sex
    
        def score(self):
            print('%s is scoring' %self.name)
    
    print(OldboyTeacher.__dict__)
    # {'__module__': '__main__', 'school': 'Oldboy', '__init__': <function OldboyTeacher.__init__ at 0x00000000027D9730>, 'score': <function OldboyTeacher.score at 0x00000000027D97B8>, '__dict__': <attribute '__dict__' of 'OldboyTeacher' objects>, '__weakref__': <attribute '__weakref__' of 'OldboyTeacher' objects>, '__doc__': None}
    """
    
    # class Mymeta(type): #但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
    #     pass
    #
    # class OldboyTeacher(object): #OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    #     school = 'Oldboy'
    #
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def score(self):
    #         print('%s is scoring' %self.name)
    #
    #     def __call__(self, *args, **kwargs):
    #         print(self) #<__main__.OldboyTeacher object at 0x00000000021E1668>
    #
    #         print(args) #(1, 2)
    #
    #         print(kwargs) #{'a': 1, 'b': 2}
    
    
    # tea1=OldboyTeacher('egon',18,'male')
    # tea1(1,2,a=1,b=2)
    
    """
    总结:对象之所以可以调用,是因为对象的类中有一个函数__call__
    推导:如果一切皆对象,那么OldboyTeacher也是一个对象,该对象之所以可以调用,肯定是这个对象的类中也定义了一个函数__call__
    """
    
    '''
    实例化OldboyTeacher,或者说调用OldboyTeacehr
    1先产生一个空对象
    2 执行__init__方法,完成对象的初始属性操作
    3 返回初始化好的那个对象
    推导:调用OldboyTeacher(..)就是在调用OldboyTeacher的类中的__call__ 那么在该__call__中就需要最上述三件事
    '''
    # 自定义元类来控制类的调用(类的实例化过程)
    # class Mymeta(type):#但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
    #     def __call__(self, *args, **kwargs):
    #         # 1 先产生一个空对象
    #         tea_obj=self.__new__(self) #tea_obj是OldboyTeacher这个类的对象
    #
    #         # 2 执行__init__方法,完成对象的初始属性操作
    #             # 这是用到了属性查找
    #         self.__init__(tea_obj, *args, **kwargs)
    #         print(tea_obj.__dict__)
    #         # {'name': 'egon', 'age': 18, 'sex': 'male'}
    #
    #         # tea_obj.__dict__={('_%s__%s'%(self.__name__,k)):v for k,v in tea_obj.__dict__.items()}
    #         #可以对外界隐藏属性
    #
    #         # 3 返回初始化好的那个对象
    #         return tea_obj
    #
    # class OldboyTeacher(object,metaclass=Mymeta):#OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    #     school='oldboy'
    #
    #     def __init__(self,name,age,sex):
    #         self.name=name
    #         self.age=age
    #         self.sex=sex
    #
    #     def score(self):
    #         print('%s is scoring'%self.name)
    
    # tea1=OldboyTeacher('egon',18,'male') #会触发OldboyTeacher类(即元类)中的__call__函数
    # print(tea1)
    # <__main__.OldboyTeacher object at 0x0000000001E51898>
    
    # print(tea1.__dict__)
    # {'name': 'egon', 'age': 18, 'sex': 'male'}
    
    
    # print(object.__new__)
    # print(type.__new__)
    
    
    
    '''
    
    1 异常处理
        错误:
            语法上的错误:应该在程序运行前就修改正确
            逻辑上的错误:
                1 当我们可以预知程序发生错误的添加,应该用if判断去规避错误
                    AGE=10
                    age =input('>>: ').strip()
                    if age.isdigit():
                        age=int(age)
                        if age >AGE:
                            print('too big')
                        else:
                            print('必须输入数字')
    
                2 当我们无法预知程序发生错误的条件,也就是说错误一定会发生,那么我们应该
                try...except去补救
        语法:
            try:
                被检测的子代码块
            except 异常类型1 as e:
                匹配成功异常类型1 执行的子代码块
    
            except 异常类型2 as e:
                匹配成功异常类型2 执行的子代码块
    
            except 异常类型3 as e:
                匹配成功异常类型3 执行的子代码块
    
            except Exception as e:
                万能异常
    
            else:
                被检测的子代码块没有发生异常时执行的代码块
    
            finnally:
                无法被检测的子代码块有无异常发生,都会执行,通常应该在这里进行回收资源的操作
    
    
    元类:
        1 什么是元类:总的来说元类就是类的类
            1 一切皆对象: 元类 --(实例化)-->自定义的类--(实例化)-->自定义的对象
                1 调用自定义的列得到自定义的对象
                2 调用元类得到是自定义的类
    
            2 class关键字的底层原理
                1 先拿到类名'Foo'
                2 在拿到类的基类们(object,)
                3 然后拿到类的名称空间{。。。}
                4 调用元类实例化得到自定义的类 Foo=type('Foo',(object,),{...})
    
        2 为什么要用元类
            为了控制class关键字的行为
    
        3 如何控制元类
            1
                class Mymeta(type): #必须是继承type的类才能称之为自定义元类,否则就是一个普通的类
                    pass
    
                class OldBoyTeacher(metaclass=Mymeta):
                    pass
            2 自定义元类控制类的产生
                class Mymetea(type):
                    def __init__(self,class_name,class_bases,class_dic):
                        pass
    
                class OldBoyTeacher(metaclass=Mymetea): #OldBoyTeacher=Mymeta('OldBoyTeacher',(object,),{...})
                    school='OldBoy'
    
                    def __init__(self,name):
                        self.name=name
    
                    def score(self):
                        pass
    
            3 自定义元类控制类的调用(即控制类的实例化得到对象的过程)
                class Mymeta(type):
                    def __init__(self,*args,**kwargs): #self=OldBoyTeacher这个类,arges与kwarges用来接收对象调用时括号内传入的参数
                        #1 产生一个OldBoyTeacher类空对象
                        obj=self.__new__(self)
    
                        #2 调用OldBoyTeacher下的__init__方法完成对空对象的初始化操作
                        self.__init__(obj,*args,**kwargs)
    
                        #3 返回初始化好的对象
                        return obj
    
    
                class OldBoyTeacher(metaclass=Mymeta):
                    school='OldBoy'
    
                    def __init__(self,name):
                        self.name=name
    
                    def score(self):
                        pass
    
    
                tea1=OldBoyTeacher('egon')
    
            4 属性查找
    
    
    '''
    """
    # 单列模式实现方式一
    import settings  #IP='1.1.1.1' PORT=3306
    class MySQL:
        _instance=None
    
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
        @classmethod
        def form_conf(cls):
            if cls._instance is None:
                cls._instance=cls(settings.IP,settings.PORT)
            return cls._instance
    
    
    # obj1=MySQL.form_conf()
    # obj2=MySQL.form_conf()
    # obj3=MySQL.form_conf()
    # print(obj1)
    # print(obj2)
    # print(obj3)
    # <__main__.MySQL object at 0x00000000021B17F0>
    # <__main__.MySQL object at 0x00000000021B17F0>
    # <__main__.MySQL object at 0x00000000021B17F0>
    
    # 传参是相当于实例化走init
    # obj4=MySQL('1.2.3',3302)
    # print(obj4)
    # <__main__.MySQL object at 0x0000000001E818D0>
    
    
    """
    '''
    # 单例模式实现方式二: 装饰器
    import settings
                #cls是被装饰函数 装饰器可以装饰任意类型,被装饰对象也可以是任意类型
    def singleton(cls):
        _instance=cls(settings.IP,settings.PORT)
    
        def wrapper(*args,**kwargs):
            if len(args) !=0 or len(kwargs) !=0:
                #有参数自己实例化
                obj=cls(*args,**kwargs)
                return obj
            return _instance
        return wrapper
    
    @singleton #MySQL=singleton(MySQL) #MySQL=wrapper
    class MySQL:
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
    # obj=MySQL('1.1.2.1',3306) #obj=wrapper('1.1.2.1',3306)
    # print(obj.__dict__)
    # {'ip': '1.1.2.1', 'port': 3306}
    obj1=MySQL()
    obj2=MySQL()
    obj3=MySQL()
    obj4=MySQL('1.2.3.1',3301)
    print(obj1)
    print(obj2)
    print(obj3)
    print(obj4)
    # <__main__.MySQL object at 0x00000000027C1668>
    # <__main__.MySQL object at 0x00000000027C1668>
    # <__main__.MySQL object at 0x00000000027C1668>
    # <__main__.MySQL object at 0x0000000001E51860>
    
    '''
    """
    # 单例模式实现方式三
    
    import settings
    class Mymeta(type):
        def __init__(self,class_name,class_bases,class_dic):
    
            #self=MySQL这个类
            # MySQL.__instance=MySQL(settings.IP,settings.PORT)
            self.__instance=self(settings.IP,settings.PORT)
    
        def __call__(self, *args, **kwargs):
            #self=MySQL这个类
            if len(args) !=0 or len(kwargs) !=0:
                obj=self.__new__(self)
                self.__init__(obj,*args, **kwargs)
                return obj
    
            return self.__instance
    
    class MySQL(metaclass=Mymeta):
        def __init__(self,ip,port):
            self.ip=ip
            self.port=port
    
    obj1=MySQL()
    obj2=MySQL()
    obj3=MySQL()
    obj4=MySQL('1.2.3.1.1',2231)
    print(obj1)
    print(obj2)
    print(obj3)
    print(obj4)
    <__main__.MySQL object at 0x00000000027C1828>
    <__main__.MySQL object at 0x00000000027C1828>
    <__main__.MySQL object at 0x00000000027C1828>
    <__main__.MySQL object at 0x00000000027C1898>
    """
    
    '''
    # 单列模式实现方式四:
            # singleton
            # import settings
            #
            # class MySQL:
            #     print('run....')
            #     def __init__(self, ip, port):
            #         self.ip = ip
            #         self.port = port
            #
            # instance=MySQL(settings.IP,settings.PORT)
    
    def f1():
        from singleton import instance
        print(instance)
    
    def f2():
        from singleton import instance,MySQL
        print(instance)
        obj=MySQL('1,2.1.1',3302)
        print(obj)
    
    f1()
    f2()
    
    run....
    <singleton.MySQL object at 0x00000000021A18D0>
    <singleton.MySQL object at 0x00000000021A18D0>
    <singleton.MySQL object at 0x0000000002118BA8>
    '''
  • 相关阅读:
    Linux命令-chmod、chown和chgrp
    UUID是如何保证全局唯一的
    Java实现HTML转换为PDF的常见方法
    Java内存溢出详解
    Java 版本6下载大全
    spring 标签
    java 静态成员访问
    Java开发之@PostConstruct执行顺序
    Java集合和数组的区别
    集合转数组的toArray()和toArray(T[] a)方法
  • 原文地址:https://www.cnblogs.com/lakei/p/10785734.html
Copyright © 2011-2022 走看看