反射
1.反射
反射指的是一个对象应该具备可以检测,修改,增加自身属性的能力。反射可以通过字符串操作属性,共涉及到四个属性,这四个函数就是普通的内置函数,没有双下划线,与print等等没有区别。
# hasattr getattr setattr delattr的用法 class Person: def __init__(self,name,age,gender): self.name =name self.age = age self.gender = gender p = Person('li',18,',man') # print(p.age) # >>>:18 # print(hasattr(p,'name')) # >>>:True 判断某个对象是否存在某个属性 if hasattr(p,'name'): print(getattr(p,'name',None)) #从对象中取出属性,第三个值为默认位,当属性不存在时就返回出默认值 #为对象添加新的属性 setattr(p,"id",'91') print(p.id) # 从对象里面删除属性 delattr(p,"id") delattr(p,'age') print(p.__dict__)#里面中的id,age属性被删除了 # >>>:{'name': 'li', 'gender': ',man'}
使用场景:反射其实就是对属性的增删改查,如果直接使用__dict__来操作,语句繁琐,不好理解。另外一个最主要的问题是,如果对象不是自己写的,而是第三方提供的,我就必须判断这个对象是否满足我需要的属性和方法。
2.元类 metaclass
元类是用来创建类的类,把要创建的类看成是元类的对象。对象是通过是通过实例化产生的,如果类也是对象的话,必然类对象也是由另一个类实例化产生的。默认情况下所有类的元类都是type。
只要继承了type,那么这个类就变成了一个元类。
#自己直接定义的一个元类
class MyType(type): def __init__(self,class_name,bases,dict): super().__init__(class_name,bases,dict) print(class_name,bases,dict) if not class_name.istitle(): raise Exception("类名格式不对") class Duck(metaclass=MyType): # 为duck类指定了元类为MyType pass
>>>:Duck () {'__module__': '__main__', '__qualname__': 'Duck'}
3.元类中的call方法
当你调用累对象时会自动调用元类中的__call__方法,并将这个类本身作为第一个参数传入,以及后面的一堆差数。当覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建。
使用场景:当你想要控制对象的创建过程时,就覆盖call方法;当你想要控制类的创建过程时,就覆盖init方法。
# 实现将对象的所有属性名称转大写 class MyType(type): def __call__(self, *args, **kwargs): new_args = [] for a in args: new_args.append(a.upper()) print(new_args) print(kwargs) return super().__call__(*new_args,**kwargs) class Person(metaclass=MyType): def __init__(self,name,gender): self.name = name self.gender = gender p = Person("jack","woman") print(p.name)#>>>:JACK print(p.gender)#>>>:WOMAN
注意:一旦覆盖了call必须要调用父类的call方法来产生对象并返回这个对象。