今日内容 元类 异常
1:元类:
什么是元类: 就是产生类的类 简称为元类 metaclass
用途:对类的产生设定一些规定,
作用: 创建新的元类继承type,通过覆盖"__init__"完成对类的限制. 如例子对类名和方法的限制
什么时候用 : 需要对类进行一些限制的时候
2: type 的两种意思: 一种是类型的 比如 print(isinstance('a', str)) 二是类的元类
type(对象) 就是对象的类型
type(类名,父类们,名称空间) 产生的 就是一个新的类 名称空间实际上就是一个字典 用来存贮数据的
3:类的组成部分 1)类名 2)父类们 3)名称空间
# 自定义元类
class Mymetaclass(type): # 创建一个新的元类
pass
# 使用自定义元类
class A(metaclass=Mymetaclass): # 继承元类
pass
4:元类中 __init__ __new__ __call__ 函数
1)__init__在元类中的应用
在实例化对象时会自动调用__init__方法,会将对象本身作为第一个参数传递过去
因为类也是对象 在实例化类对象时也会自动调用__init__方法,会见类对象作为第一个参数传递进去,
也会传递三个参数 分别是 类名称 父类们 名称空间
__init__在元类中的作用: 创建新的元类继承type,通过覆盖"__init__"完成对类的限制.
class A:
def __init__(self,name):
self.name= name
a= A()# 实例化对象
class MyMetaclass(type):
def __init__(self,class_name,bases,name_dict): #
'''
自定义元类
:param class_name: 类名称
:param bases: 父类们
:param name_dict: 名称空间
'''
pass
class B(metaclass=MyMetaclass): # 此时运行到class 就是实例化类对象B了
pass
# 案例 限制类名必须首字母大写 控制类中方法名必须全部小写
# 分析:那么可以元类中限制类的创建条件
# 因为类名和属性和方法都是存储到类中名称空间的 类名下对应下是属性和方法 那么可以通过操作名称空间进行限制
class MyMetaclass(type):
def __init__(self,class_name,bases,name_dict):
# 元类的self代表的就是类对象
super().__init__(class_name,bases,name_dict)
# 对父类进行初始化
# 对类名首字母进行限制 必须大写字母
if not class_name.istitle():
print('类名必须大写')
# else: 这一行可不需要
raise Exception # 否则就报异常
# 取出类中的属性和方法
for k in name_dict:
if str(type(name_dict[k])) == "<class 'function'>": # "<class 'function'>" 就是类的方法
if not k.islower():
print('方法首字母必须小写')
raise Exception
class student(object,metaclass=MyMetaclass): # 类名小写报错 提示 类名必须大写 根据上面元类的限制类名的方法
NAME = 10
def say_hai(self):
print("============")
# class Student(metaclass=MyMetaclass): # 方法名大写报错 提示 方法名必须小写
# name = 10
# def Say(self):
# print('111111111111111111111')
2)元类中的__new__方法 (不常用)
__new__创建类对像的时候执行 先于__init__运行
作用:创建类对象
注意:如果覆盖了`__new__` 一定也要调用type中的`__new__`并返回执行结果
__new__与__init__的区别 1)先于__init__执行 2)__new__是创建类对象的(指的是元类的对象) __init__是实例化类对象的
class MyMetaclass(type):
def __init__(self,class_name,bases,name_dict):
pass
def __new__(cls, *args, **kwargs):
# pass
# cls表示类自己 即MyMetaclass
return type.__new__(cls,*args,**kwargs)
class People(metaclass=MyMetaclass):
pass
print(People)
# __new__作用是创建类的 必须要返回值 没有无法创建对象的 当把return type.__new__(cls,*args,**kwargs)注释掉
# print(People) 的结果是None
# 案例 要求每个类中必须含有__doc__属性 就是必须要有注释的意思
class MyMetaclass(type):
def __init__(self,class_name,bases,name_dict):
super().__init__(class_name,bases,name_dict)
# if not self.__doc__:
# raise Exception # 两种方法都行
# 或者
if not('__doc__' in name_dict and name_dict['__doc__']): # __doc__在名称空间还里
raise Exception
# class A(metaclass=MyMetaclass):
# pass # 无注释 报错
class B(metaclass=MyMetaclass): #有注释不报错
'''
'''
3)__call__
执行时机:在元类中,调用类时执行
作用:控制对象的创建过程
案例 用__call__来实现单例模式 单例模式就是仅有一个实例的意思
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 People(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 aunt is 龙妈'% self.name)
class Stu(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 aunt is 龙妈' % self.name)
p1 = People('jeck',18,'man')
print(p1) # 地址都是一样的
p2 = People('tom',22,'man')
print(p2) # 地址都是一样的
# 案例 单例模式制作一个QQ播放器案例
class MyMetaclass(type):
def __init__(self,class_name,bases,name_dict):
super().__init__(class_name,bases,name_dict)
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=MyMetaclass):
def __init__(self,voice_value,repeat=None): # repeat 重复的意思
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)
q1 = QQplayer(100,True)
q1.play('多远多要在一起')
q2 = QQplayer(80,True)
q2.play('泡沫')
# 正在播放多远多要在一起
# 停止播放多远多要在一起
# 正在播放泡沫
# 1. hasattr(object, 'name')
#
# 判断object对象中是否存在name属性,当然对于python的对象而言,属性包含变量和方法;有则返回True,没有则返回False;
# 需要注意的是name参数是string类型,所以不管是要判断变量还是方法,其名称都以字符串形式传参;getattr和setattr和delattr也同样;