day29
# 类也是对象 是由type类实例化产生的
# print(type(1))
#
#
# A.__dict__
#
# 一个类由三个部分组成
# 类名字
# 类的父类们
# 名称空间
# class MyClass(object):
#
# a = 10
#
# def say_hi(self):
# pass
动态语言
可以在运行期间 动态生成类 修改对象属性
静态语言
"""
obj = type("TestClass",(object,),{})
print(obj)
class B(object): # type("B",(object,),{"name":"rose"})
name = "rose"
# 模拟解释器创建类的过程
class_name = "C"
bases = (object,)
name_dict = {"name":"jack","test1":test1,"test2":test2}
名字,父类,名称空间,type
# exec 可以执行字符串形式的python代码 并且会把执行过程中产生的名字 放到局部名称空间中
# class_text = """
# class A:
# def test(self):
# print(self)
# """
# loca2 = {}
# exec(class_text,None,loca2)
# print(loca2)
###############################
#############可以创建一个元类,然后对已经有的功能进行改动
class person():
def __init__(self,name):
self.name = name
def SAYHI(self):
print(self.name)
# 类名必须大写开头 方法名必须全部小写
# 应用场景:用于限制类 满足某些条件 例如上述要求
# type类已经具备了创建类的能力 ,但是现在不能满足我们的需求
# 需要对已有的功能进行扩展或修改
# 方式
# 1.直接修改源代码 行不通
# 2.自己定义新的元类
class MyMetaClass(type):
pass
# 默认创建类时 是找的type来实例化的
class Person(metaclass=MyMetaClass):
pass
class Student:
def __init__(self):
pass
pass
print(type(Person))
print(type(Student))
s = Student()# 实例化对象时 ,1.产生空对象 2.自动执行__init__
# 创建类对象时也是一样的 会先创建空的类对象 再调用__init__()方法
# Person = MyMetaClass()
##########################################
创建类的时候发生了什么
class MyMetaClass(type):
def __init__(self,class_name,bases,name_dict):
# 元类中的self表示的都是类对象
# 不要忘记调用父类的初始化
super().__init__(class_name,bases,name_dict)
print(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():
print("方法名称必须全小写 傻蛋!")
raise Exception
pass
# 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们 名称空间
class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{})
NAME = 10
def say(self):
print("SAY")
pass
#################################################
元类中的__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
# print("new")
# print(args,kwargs)
return type.__new__(cls,*args,**kwargs) # 如果覆盖__new__ 一定要写上这行代码
class Person(metaclass=MyMetaClass):
pass
print(Person)
# 就算__init__中什么都不写 这个类对象其实已经创建完成了 该有的属性都有了
# 这是与普通类不同之处
# print(Person.__name__)
# class Student:
# def __init__(self,name):
# pass
#
# s = Student("张三")
#
# s.name
#######################################################
练习
# 需求: 要求每个类必须包含__doc__属性 __doc__ 用于访问一个对象的注释信息
# class A:
# """
# this is a Class
# author is jerry
# """
# pass
# print(A.__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 Exception
# class Person(metaclass=DocMeatClass):
# pass
print(type(object))
########################################################
__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 = 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 Person:
obj = None
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)
@classmethod
def get_instance(cls):
if not cls.obj:
obj = cls("囧雪诺",20,"man")
cls.obj = obj
print("创建新的了")
return cls.obj
p1 = Person.get_instance()
p1.say()
print(p,p1)
p2 = Person.get_instance()
p2.say()
p3 = Person.get_instance()
p3.say()
#################################################
元类实现单例
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): # 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, p2)
stu = Student("布兰",16,"man")
print(p1 , stu)
stu1 = Student("布兰",16,"man")
stu2 = Student("布兰",16,"man")
stu3 = Student("布兰",16,"man")
print(stu1,stu2,stu3)
#######################################################
单例案例
class Single(type):
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 QQPlayer(metaclass=Single):
def __init__(self,voice_value,repeat=False):
self.voice_value = voice_value
self.repeat = repeat
def play(self,file_path):
if hasattr(self,"file_path"):
self.stop()
print("正在播放%s" % file_path)
self.file_path = file_path
def stop(self):
print("%s停止播放" % self.file_path)
player1 = QQPlayer(100,True)
player1.play("如果他是一条狗.mp3")
player2 = QQPlayer(100,True)
player2.play("如果你不是一条狗.mp3")
player3 = QQPlayer(100,True)
player3.play("你的滑板鞋.mp3")
###########################
常见异常
# 常见异常
- AttributeError 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x
- IOError 输入/输出异常;无法打开文件或无法读写
- ImportError 无法引入模块或包;基本上是路径问题或名称错误
- SyntaxError Python语法错误异常,代码不能编译
- IndentationError 缩进异常;代码没有正确缩进
- IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
- KeyError 试图访问字典里不存在的键
- KeyboardInterrupt Ctrl+C被按下
- NameError 使用一个还未被赋予对象的变量
- TypeError 传入对象类型与要求的不符合
- UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
- ValueError 传入一个调用者不期望的值,即使值的类型是正确的
##################################
# 抛出异常
当我们的程序在执行过程中由于接收到的参数不正确或者其他情况导致,后续代码无法执行时,可以主动抛出异常
使用raise关键字,后面跟任意Exception的子类或子类实例
```:point_up_2:
# 直接抛出异常
raise TypeError
# 直接抛出异常 并附加错误信息
raise TypeError("类型错误")
##########################################################
# 断言
断言是就是断定的意思,当一些代码的执行必须满足某个条件时,就需要先断定条件在继续执行,当然你可以使用`if`判断来处理
`assert` 后面跟条件即可 如果条件成立则正常执行,否则抛出`AssertionError`
**断言可以简化代码 但是无法知道异常的详细信息**
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")
############################################################3