阅读目录
元类
__inti__方法
__new__方法
__call__方法
单例模式
exec与eval区别
异常处理语法
##元类
#什么是元类? 一切皆对象 类也是对象,可以把一个类当成普通对象来使用,比如存储到列表中,或者作为参数传给函数等等... 对象是如何产生的? 通过类实例化产生的 类对象 是由type实例化产生的 class AClass: pass print(type(AClass)) #我们可以手动调用type来实例化产生一个类 #一个类由三个部分组成 1.类的名称 我是谁 2.类的父类们 我从哪里来 3.类的名称空间 我有什么 #type源码中 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)
#用来干啥
“”“
当我们需要高度定制类时,如限制类名必须大写开头等等...
就需要使用元类,但是元类type中的代码 无法被修改 ,只能创建新的元类(继承自type) 通过覆盖__init__
来完成对类的限制
”“”
#使用元类
#1、如何自定义元类
pass
class Person(metaclass=MyMetaClass):
pass
实例化对象时会自动执行类中的__init__
方法, 类也是对象 ,在实例化类对象时会自动执元类中的__init__
方法
并且传入类的三个必要参数,类的名字,父类们,名称空间
当然会自动传入类对象本身作为第一个参数
def __init__(self,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])) == "<class 'function'>":
if not k.islower():
raise Exception
pass
class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{})
NAME = 10
def say(self):
print("SAY")
pass
元类中的new方法会在创建类对象时执行,并且先于init方法
作用是创建一个类对象
class A(metaclass=MyMetaClass):
pass
#1.执行MyMetaClass的__new__
方法 拿到一个类对象
#2.执行MyMetaClass的__init__
方法 传入类对象以及其他的属性 ,进行初始化
注意:如果覆盖了__new__
一定也要调用type中的__new__
并返回执行结果
#使用new方法也可以完成定制类的工作 和init有什么区别?
所以如果对性能要求高的话 可以选在在new中完成定制 如果发现有问题,就不用创建类对象了
# super().__init__(class_name,bases,name_dict)
print("init")
pass
# 其作用时用于创建新的类对象的
# 注意这里必须调用type类中的__new__ 否则将无法产生类对象 并且返回其结果
def __new__(cls, *args, **kwargs):
# cls 表示元类自己 即MyMetaClass
# print("new")
# print(args,kwargs)
return type.__new__(cls,*args,**kwargs) # 如果覆盖__new__ 一定要写上这行代码
class Person(metaclass=MyMetaClass):
pass
# 这是与普通类不同之处
# class Student:
# def __init__(self,name):
# pass
#
# s = Student("张三")
#
# s.name
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
#或者如下
# if not name_dict.get("__doc"):
# raise Exception
class Person(metaclass=DocMeatClass):
""""""
pass
元类中的 call方法会在调用类时执行,
可以用于控制对象的创建过程
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)
# __call__ 类对象要产生实例时执行
def __init__(self,name,gender,age):
print(self)#类的对象
self.name = name
self.gender = gender
self.age = age
print(s.age)
print(s.gender)
class Person(metaclass=MyMeta):
def __init__(self,name,gender):
self.name = name
self.gender = gender
print(Person)#类的对象
p = Person("rose","man")
print(p.name)
#元类的单例模式
#什么是单例: 某个类如果只有一个实例对象,那么该类成为单例类 单例的好处: 当某个类的所有对象特征和行为完全一样时,避免重复创建对象,浪费资源 #示例: class SingletonMetaClass(type): #创建类时会执init 在这为每个类设置一个obj属性 默认为None def __init__(self,class_name,bases,name_dic): super().__init__(class_name,bases,name_dic) 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): # Person = SingletonMetaClass("Person",(object,),{}) 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") # p1.say() p2 = Person("jon snow",18,"man") # # p1.say() # p3 = Person("jon snow",18,"man") # p1.say() # print(p1 is p2) #True stu = Student("布兰",16,"man") print(p1 , stu) stu1 = Student("布兰",16,"man") stu2 = Student("布兰",16,"man") stu3 = Student("布兰",16,"man") print(stu1,stu2,stu3) #总结 Person类创建多个对象时,因为self.obj在创建了第一次以后被赋值,后续在创建对象就不会再重新创建了,又来了Student类也要创建对象,初始化时self.obj被赋予默认值None,又可以重新创建另外一个对象了,然而又想在创建另一个Student类,又创建不了多个了,只使用同一个
##exec与eval
“”“ exec用于执行字符串形式的python代码 只要符合python都能执行 ,并且可以指定将执行产生的名字放入某个名称空间 eval 用于把一个字符串当成一个表达式来执行,且只能执行简单的表达式,不能有任何的特殊语法,返回表达式执行结果 ”“” #示例一:exec class_text = """ class A: def test(self): print(self) """ loca2 = {} exec(class_text,None,loca2) print(loca2) #eval(class_text) #报错 #示例二:eval x=100 y=200 s="x+y" print(eval(s))#200 ls={"x":1,"y":2} print(eval(s,None,ls))#3 gs={"x":10,"y":20} print(eval(s,gs,ls))#3 执行locals中的先---ls
##异常
# 什么是异常 异常是程序运行过程中发生的非正常情况,是一个错误发生时的信号 异常如果没有被正确处理的话,将导致程序被终止,这对于用户体验是非常差的,可能导致严重的后果 处理异常的目的就是提高程序的健壮性 # 异常的分类 python解释器在执行代码前会先检查语法,语法检查通过才会开始执行代码 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 是异常追踪信息 用于展示错误发生的具体位置 以及调用的过程 其中 包括了 错误发生的模块 文件路径 行号 函数名称 具体的代码 最后一行 前面是错误的类型 后面 错误的详细信息 在查找错误时 主要参考的就是详细信息 #异常的处理 异常发生后 如果不正确处理将导致程序终止,我们必须应该尽量的避免这种情况发生yufa #异常语法 语法: try: 可能会出现异常的代码 放到try里面 except 具体异常类型 as e: 如果真的发生异常就执行except #如何正确处理异常 1. 当发生异常 不是立马加try 要先找出错误原因并解决它 2. try 仅在 即使你知道为什么发生错误 ,但是你却无法避免 例如 你明确告诉用户 需要一个正确文件路径 然而用户依然传入了错误的路径 如 socket 双方都要使用管道 ,但是如果一方有由于某些原因强行关闭了 ,即使你知道原因也无法避免出错 那就只能try 保证程序正常结束 总结一句话:能不加try 就不加try #自定义异常类 当系统提供异常类不能准确描述错误原因时 就可以自定义异常类 继承自Exception即可 class MyException(Exception): pass #主动抛异常 “”“ 什么时候需要主动抛出异常 当我们做功能的提供者,给外界提供一个功能接口 但是使用者不按照相应的方式来使用,或者参数类型不正确等原因,导致功能无法正常执行时,就应该主动抛出异常 主动抛出异常使用raise 关键字 后面可以跟任何Exception的子类 或是 对象 ”“” #断言assert “”“ 断言 其实可以理解为断定的意思 即非常肯定某个条件是成立的 条件是否成立其实可以使用if来判断 其存在的目的就是 为了简化if 判断而生的 ”“” #示例 class FileTypeException(Exception): pass class Player: def play(self,path): # if not path.endswith("mp3"): # # print("文件类错误!") # # z主动抛出异常 # raise FileTypeException("仅能播放mp3格式.....") # print("播放%s" % path) assert path.endswith("mp3") print("播放%s" % path) p = Player() p.play("xxx.mp4")