python_day29_元类

今日内容 元类  异常
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也同样;


猜你喜欢

转载自www.cnblogs.com/wakee/p/10921960.html