1、元类
什么是元类:
一切皆对象,类也是对象,可以把一个类当成普通对象来使用,比如存储到列表中或者作为参数传给函数等等....
对象是如何产生的? 通过类实例化产生的
类对象 是由 type 实例化产生的
class AClass:
pass print(type(AClass))我们可以手动调用 type 来实例化产生一个类;
类的三个组成部分:
1. 类的名称 我是谁
2. 类的父类们 我从哪来
3. 类的名称空间 我有什么(名称空间里存了什么)
type(类名,父类元组,名称空间) #将会返回一个新的类
type(对象) # 将会返回这个对象的类型
当定义一个class时解释器会自动调用 type 来完成类的实例化
#模拟解释器创建类对象:
def test1(a):
print(a)def test2(self,b):
print(self,b)class_name = "C"
bases = (object,) name_dict = {"name":"jack","test1":test1,"test2":test2}C = type(class_name,bases,name_dict)
# print(C) c1 = C() # print(c1) c1.test2(100)补充exec与eval:
***exec 用与执行字符串形式的 python 代码,只要符合 python 都能执行,并且可以指定将执行产生的名字放如某个名称空间
***eval 用于执行简单的表达式,不饿能有任何的特殊语法
class_text =
class A: def test(self): print(self) loca2 = {} exec(class_text,None,loca2) print(loca2) #eval(class_text) #报错元类:用于产生类的类,称之为元类
元类 :metaclass 只要看见它就要想起来这是元类
定义元类时,尽量在类名后添加MetaClass 方便阅读
元类的作用(用来做什么)
当我们需要高度定制类时,如限制类名必须答谢开头....
就需要使用元类,但是元类 type 中的代码 无法被修改,只能创建新的元类(继承自 type)通过覆盖__init__来完成对垒起的限制
元类的使用
如何定义元类:
class MyMetaClass(type):
pass# 使用自定义元类
class Person(metaclass=MyMetaClass): pass__init__方法(*****)
实力化对象时会自动执行类中的__init__方法,类也是对象在实列化类对象时会自动执行元类中的__init__方法
并且会传入类的三个必要参数,类的名字,分类们,名称空间
当然会自动传入类对象本身作为第一个参数
class MyMetaClass(type): def __init__(self,class_name,bases,name_dict): super().__init__(class_name,bases,name_dict) # 类名必须首字母大写 否则直接抛出异常 if not class_name.istitle(): print("类名必须大写 傻x!") raise Exception # 控制类中方法名必须全部小写 for k in name_dict: if str(type(name_dict[k])) == "": if not k.islower(): raise Exception pass # 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们 名称空间 class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{}) NAME = 10 def say(self): print("SAY") pass
__new__方法(***)
元类中的new方法会在创建类对象时执行,并且先于 init 方法
作用是创建一个类对象
class A(metaclass=MyMetaClass):
pass
1.执行MyMetaClass的__new__方法 拿到一个类对象
2.执行MyMetaClass的__init__ 方法 传入类对象以及其他的属性,进行初始化
注意:如果覆盖了__new__一定也要调用 type 中的__new__并返回执行结果
需求: 要求每个类必须包含__doc__属性
class DocMeatClass(type): def __init__(self,class_name,bases,name_dict): super().__init__(class_name,bases,name_dict) # if not("__doc__" in name_dict and name_dict["__doc__"]): # raise Exception # 或者如下 if not self.__doc__: raise Exception class Person(metaclass=DocMeatClass): """""" pass
需求: 要求每个类必须包含__doc__属性 __doc__ 用于访问一个对象的注释信息
# 你要控制类的创建 那就自定义元类 覆盖__init__ class DocMeatClass(type):def __init__(self,class_name,bases,name_dict):
super().__init__(class_name,bases,name_dict) # if not("__doc__" in name_dict and name_dict["__doc__"]): # raise Exception if not self.__doc__: raise Exceptionclass Person(metaclass=DocMeatClass):
pass__call__方法(*****) 元类中的 call 方法会在调用类时执行 可以用于控制对象的创建过程
class MyMeta(type):
# 获得某个类的实例
def __call__(self, *args, **kwargs): print("call") # return super().__call__(*args,**kwargs) new_args = [] for i in args: if isinstance(i,str): new_args.append(i.upper()) else: new_args.append(i) return super().__call__(*new_args,**kwargs)# 注意注意注意: __new__ __init__ 是创建类对象时还会执行
# __call__ 类对象要产生实例时执行class Student(metaclass=MyMeta):
def __init__(self,name,gender,age): self.name = name self.gender = gender self.age = ages = Student("jack","woman",18)
print(s.age) print(s.gender) class Person(metaclass=MyMeta): def __init__(self,name,gender): self.name = name self.gender = genderp = Person("rose","man")
print(p.name)总结:当你要定制类时,就要地综艺元类并覆盖__init__ 方法
元类实现单利模式
什么是单利:
莫各类如果只有一个实列化对象,那么该类成为单例类
单例的好处:
当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源
案例:
class SingletonMetaClass(type):
#创建类时会执init 在这为每个类设置一个obj属性 默认为None def __init__(self,a,b,c): super().__init__(a,b,c) self.obj = None # 当类要创建对象时会执行 该方法 def __call__(self, *args, **kwargs): # 判断这个类 如果已经有实例了就直接返回 从而实现单例 if self.obj: return self.obj# 没有则创建新的实例并保存到类中
obj = type.__call__(self,*args,**kwargs) self.obj = obj return obj2、异常
什么是异常
异常是程序运行过程中繁盛的非正常情况,是一个错误发生时的信号
异常如果没有被正确处理的话,将导致程序被终止,这对于用户体验是非常差的,可能导致严重搞得后果
处理异常的目的就是提高程序的健壮性
异常的分类
1.语法检测异常 作为一个合格的程序员 是不应该出现这种低级错误
2.运行时异常
已经通过语法检测,开始执行代码,执行过程中发生异常 称之为运行时异常
TypeError: 'int' object is not subscriptable 对象不能被切片 TypeError: 'list' object is not callable 对象不能被调用 IndexError: list index out of range 索引超出范围 TypeError: 'builtin_function_or_method' object is not iterable 对象不能被迭代 KeyError: 'xxx' 不存在这个key FileNotFoundError: [Errno 2] No such file or directory: 'xxxxx' 文件找不到
Traceback (most recent call last):
File "F:/python8期/课堂内容/day29/11.常见异常.py", line 22, in <module> with open("xxxxx") as f: FileNotFoundError: [Errno 2] No such file or directory: 'xxxxx'Traceback 是异常追踪信息 用于展示错误发生的具体位置 以及调用的过程
其中 包括了 错误发生的模块 文件路径 行号 函数名称 具体的代码最后一行 前面是错误的类型
后面 错误的详细信息 在查找错误时 主要参考的就是详细信息
重点:
必须掌握的语法
语法:
try:
可能会出现异常的代码 放到try里面
except 具体异常类型 as e:
如果真的发生异常就执行except
如何正确处理异常
-
当发生异常 不是立马加try 要先找出错误原因并解决它
-
try 仅在 即使你知道为什么发生错误 ,但是你却无法避免 例如 你明确告诉用户 需要一个正确文件路径 然而用户依然传入了错误的路径
如 socket 双方都要使用管道 ,但是如果一方有由于某些原因强行关闭了 ,即使你知道原因也无法避免出错 那就只能try 保证程序正常结束
总结一句话:能不加try 就不加try
自定义异常类
当系统提供异常类不能准确描述错误原因时 就可以自定义异常类
继承自Exception即可
class MyException(Exception): pass
主动抛出异常:
什么时候需要主动抛出异常
当我们做功能的提供者,给外界提供一个功能接口
但是使用者不按照相应的方式来使用,或者参数类型不正确等原因,导致功能无法正常执行时,就应该主动抛出异常
主动抛出异常使用raise 关键字
后面可以跟任何Exception的子类 或是 对象
raise MyException raise MyException("错误具体原因!")
断言assert
断言 其实可以理解为断定的意思
即非常肯定某个条件是成立的
条件是否成立其实可以使用if来判断
其存在的目的就是 为了简化if 判断而生的