1 元类
1 定义
元类翻译为:metaclass 只要看见它就应该想起来这是元类
我们在定义元类时 尽量在类名后添加MetaClass 方便阅读
一切皆对象
类也是对象,可以把一个类当成普通对象来使用,比如存储到列表中,或者作为参数传给函数等等...
对象是如何产生的? 通过类实例化产生的
class AClass: pass print(type(AClass)) # <class 'type'>
2 类的三大组成部分
1.类的名称 我是谁
2.类的父类们 我从哪里来
3.类的名称空间
我们可以手动调用type来实例化产生一个类 type(类名,父类元组,名称空间字典) #返回一个新的类 type(对象) #将会返回这个对象的类型
3 元类的运用
class MyMetaClass(type): pass # 使用自定义元类 class Person(metaclass=MyMetaClass): pass
4 元类中的
实例化对象时会自动执行类中的`__init__`方法, 类也是对象 ,在实例化类对象时会自动执元类中的`__init__`方法 并且传入类的三个必要参数,类的名字,父类们,名称空间 当然会自动传入类对象本身作为第一个参数
class MyMetaClass(type): def __init__(self,class_name,bases,name_dict): super().__init__(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 # 会自动调用其元类中的 __init__ 方法传入 类对象本身 类名称 父类们 名称空间 class Student(object,metaclass=MyMetaClass): # MyMetaClass("Student",(object,),{}) NAME = 10 def say(self): print("SAY") pass # 解释 class Student() 类 如果类名首字母不是大写就会报错 如果方法不是小写就会报错
元类中的new方法会在创建类对象时执行,并且先于init方法
作用是创建一个类对象
class A(metaclass=MyMetaClass):
pass
1.执行MyMetaClass的__new__
方法 拿到一个类对象
2.执行MyMetaClass的__init__
方法 传入类对象以及其他的属性 ,进行初始化
注意:如果覆盖了__new__
一定也要调用type中的__new__
并返回执行结果
使用new方法也可以完成定制类的工作 和init有什么区别?
在调用init方法前类对象已经创建完成了
所以如果对性能要求高的话 可以选在在new中完成定制 如果发现有问题,就不用创建类对象了
需求: 要求每个类必须包含__doc__
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
# 需求: 要求每个类必须包含__doc__属性 __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
元类中的 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 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
英文中叫反省 (自省)
面向对象中的反省 指的是,一个对象必须具备,发现自身属性,以及修改自身属性的能力;
一个对象在设计初期,可能考虑不够周全后期需要删除或修改已经存在的属性, 和增加属性
涉及到的方法:
hasattr 判断是否存在某个属性 getattr 获取某个属性的值 setattr 新增或修改某个属性 delattr 删除某个属性
class MY_CMD: def dir(self): os.system("dir") def ipconfig(self): os.system("ipconfig") cmd = MY_CMD() while True: name = input("请输入要执行的功能:") if hasattr(cmd,name): method = getattr(cmd,name) print(method) method() else: print("sorry this method is not exists....!")