day28
一.元类
1.使用背景
type(name,bases,dict)创建一个新的type类,类是由type类实例化产生的,而一个类由类名(str格式),基类(tuple格式)和名称空间(dict格式,key为str格式)三部分组成。
在定义一个class时,解释器会自动调用type来完成类的实例化。
2.定义
用于产生类的类,通常在类名后加MetaClass.
3.应用场景
用于限制类,满足某些条件
具体来说,当我们需高度定制类时,如限制类必须大写时等,我们就需要使用元类,但元类type中代码无法被修改,只能创建新的元类(继承自type),通过覆盖__init__函数来完成对类的限制
①__init__函数
在实例化对象时会先产生空对象,类也是一种对象,所以创建类对象也会产生空的类对象,然后再执行__init__函数,并传入类的三个必要参数:类名,父类,名称空间
eg.
class MyMetaClass(type):
# 元类中的self表示的都是类对象
def __init__(self,class_name,bases,name_dict):
# 不要忘记调用父类的初始化
super().__init__(class_name,bases,name_dict)
print(name_dict)
# 类名必须首字母大写 否则直接抛出异常
if not class_name.istitle():
print("类名必须大写!")
raise Exception
# 控制类中方法名必须全部小写
for k in name_dict:
if str(type(name_dict[k])) == "<class 'function'>":
if not k.islower():
print("方法名称必须全小写 傻蛋!")
raise Exception
pass
②__new__函数
注:和__init__均是在创建类对象时执行,__new__先执行,产生类对象,再执行__init__来对元类进行限制,如果没有__new__,系统会自执行此函数。
class MyMetaClass(type):
def __init__(self,class_name,bases,name_dict):
# super().__init__(class_name,bases,name_dict)
print("init")
pass
# 该方法会在实例化类对象时自动调用并且在__init __之前调用,用于创建新的类对象
# 注意这里必须调用type类中的__new__ 否则将无法产生类对象 并且返回其结果
def __new__(cls, *args, **kwargs):
# cls 表示元类自己 即MyMetaClass
return type.__new__(cls,*args,**kwargs)
# 如果覆盖__new__ 一定要写上这行代码
# 就算__init__中什么都不写, 这个类对象其实在__init__已经创建完成了, 该有的属性都有了,# 这是与普通类不同之处
class MyMetaClass(type):
def __init__(self):
pass
class Person(metaclass = MyMetaClass):
pass
eg:
class DocMeatClass(type):
def __init__(self,class_name,bases,name_dict):
super().__init__(class_name,bases,name_dict)
if not self.__doc__:
raise Exception
class Person(metaclass=DocMeatClass):
""""""
pass
③__call__函数
在调用类,实例化类对象时执行,控制对象的创建过程。
__call__也可用于自定义元类,在函数下的代码中进行属性的操作
eg:
class MyMeta(type):
# 获得某个类的实例
def __call__(self, *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 = age
s = Student("jack","woman",18)
print(s.age)
print(s.gender)
class Person(metaclass=MyMeta):
def __init__(self,name,gender):
self.name = name
self.gender = gender
p = Person("rose","man")
print(p.name)
二.单例模式
一种设计模式,当需要的类仅有一个实例,即可使用。
通用方法:
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 obj
class Person(metaclass=SingletonMetaClass):
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def say(self):
print("my name is %s my 姑姑 is 龙妈" % self.name)
class Student(metaclass=SingletonMetaClass):
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def say(self):
print("my name is %s my 姑姑 is 龙妈" % self.name)
p1 = Person("jon snow",18,"man")
p2 = Person("jon snow",18,"man")
print(p1, p2)
print(p1.act())
print(p2.act())
stu1 = Student("布兰",16,"man")
stu2 = Student("布兰",16,"man")
stu3 = Student("布兰",16,"man")
print(stu1,stu2,stu3)
#好处:当某个类的所有对象特征和行为完全一样,避免重复创建对象,避免资源浪费。
复习:当某个类的所有对象中只有个别特征和行为不同,我们可以将相同的特征行为放入类中,不同的特征和行为放进对象中。
当某一个类所有对象与其他类的所有对象间仅个别特征和行为不同,我们可以定义一个父类,然后将不同的特征和行为进行派生处理。
三.异常
1.定义
异常是程序运行过程中发生的非正常情况,是一个错误发生时的信号。
异常如果没有被正确处理的话,将导致程序被终止,这对于用户体验是非常差的,可能导致严重的后果。
2.目的
处理异常的目的就是提高程序的健壮性。
3.分类
①语法检测异常
②运行时异常
4.组成
Traceback 是异常追踪信息 用于展示错误发生的具体位置 以及调用的过程
其中 包括了 错误发生的模块 文件路径 行号 函数名称 具体的代码
最后一行 前面是错误的类型
后面时错误的详细信息
在查找错误时 主要参考的就是详细信息
5.语法
语法1
try:
print("start")
{"name":1}["xxx"]
print("over")
except:
print("key 不存在!")
语法2 在except中指定要处理的异常类型
try:
print("start")
{"name":1}["xxx"]
1[:]
print("over")
except KeyError:
print("出问题了")
语法3 在except中可以指定多种异常类型 使用统一的处理方案 没啥用
try:
print("start")
{"name":1}["xxx"]
1[:]
print("over")
except (KeyError,TypeError):
print("出问题了")
语法4 一个try可以跟多个except 语句 每个处理不同的异常
try:
print("start")
{"name":1}["xxx"]
1[:]
print("over")
except KeyError:
print("key不存在!!!!!")
except TypeError:
print("要操作的类型不对啊!!")
语法5 万能异常 尽量少用 因为 无法知道具体原因
try:
print("start")
{"name":1}["xxx"]
1[:]
name
print("over")
except Exception:
print("不知道啥原因 反正有问题!")
语法6 给异常对象取别名 从而访问一异常对象
之所以 能处理任何类型 是因为 Exception 是所有异常类的父类
try:
print("start")
{"name":1}["xxx"]
1[:]
name
print("over")
except Exception as e:
print("有问题! 原因为%s" % e)
print(type(e))
最常用的方式 在处理异常时 一定要记得打印一下异常信息 否则 你的程序不会出问题 但是也不会正常运行
try:
name
except NameError as e:
print(e)
6.如何处理?
2.try 仅在 即使你知道为什么发生错误 ,但是你却无法避免 例如 你明确告诉用户 需要一个正确文件路径 然而用户依然传入了错误的路径
如 socket 双方都要使用管道 ,但是如果一方有由于某些原因强行关闭了 ,即使你知道原因也无法避免出错 那就只能try 保证程序正常结束
#自定义异常
当系统提供异常类不能准确描述错误原因时 就可以自定义异常类
class MyException(Exception):
pass
#主动抛异常
当我们做功能的提供者,给外界提供一个功能接口
但是使用者不按照相应的方式来使用,或者参数类型不正确等原因,导致功能无法正常执行时,就应该主动抛出异常
raise MyException
raise MyException("错误具体原因!")
assert
表示非常肯定某个条件是成立的。
其存在的目的就是为了简化if 判断。

浙公网安备 33010602011771号