# 什么是元类: # 源自于一句话:在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> '''