元类 单例

# 什么是元类:
#     源自于一句话:在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>
'''
原文地址:https://www.cnblogs.com/lakei/p/10785734.html