python基础--反射、元类、单例设计模式
反射:reflect,反射指的是一个对象应该具备可以检测、修改、增加自身属性的能力,反射就是通过字符串操作属性
hasattr(对象,带查询的属性名称)
判断某个对象中是否存在某个属性
getattr
从指定对象中取出属性,第三个参数为默认值,当参数不存在时返回的就是默认值
setattr
为对象添加新的属性
delattr
从对象中删除属性
使用场景:
反射其实就是对属性的增删改查,但是如果直接用dict来操作的话,语法繁琐,而且不是很好理解,另外一个主要的问题是,如果对象不是我自己写的是另一方提供的,我就必须要判断这个对象是否满足我的要求,也就是是否是我要的属性和方法
框架的基石:
原因: 因为框架的设计者,不可能提前知道你的对象到底是怎么设计的,所以你提供给框架的对象 必须通过判断验证之后才能正常使用,判断验证就是反射要做的事情,当然通过__dict__也是可以实现的, 其实这些方法也就是对__dict__的操作进行了封装,
元类:metaclass
是什么:就是用于创建类的类,万物皆是对象,当然类也是对象
对象是通过类实例化产生的,如果类也是对象的话,必然类对象也是有另一个类实例化产生的
默认情况下所有累的元类都是type
好处:高度的自定义一个类,类也是对象,也有自己的类
__call__方法:当你调用对象时会自动执行元类中的__call__方法,并将这个类本身作为第一个参数传入,以及后面的一堆参数, 当覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建并返回其返回值
使用场景:
当你想要控制对象的创建过程时,就需要覆盖__call__方法
案例:将所有属性名称转换为大写
class Mytype(type): def __call__(self, *args, **kwargs): new_args = [] for i in args: new_args.append(i.upper()) return super().__call__(*new_args, **kwargs) class Person(metaclass=Mytype): def __init__(self, name): self.name = name p = Person('william') print(p.name)
一旦覆盖了call之后,就必须要调用父类的call方法来产生对象并且返回这个对象
__init__方法:
使用场景:
当你想要控制类的创建过程时,就覆盖__init__方法
__new__方法:
当你要创建对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后自动调用__init__来对这个类进行初始化操作
注意:如果你覆盖了该方法就必须保证new方法有返回值并且是对应的类对象
class Meta(type): def __new__(cls, *args, **kwargs): print(cls) # 元类自己 print(args) # 创建类需要的几个参数 类名,基类,名称空间 print(kwargs) #空的 print("new run") # return super().__new__(cls,*args,**kwargs) obj = type.__new__(cls,*args,**kwargs) return obj def __init__(self,a,b,c): super().__init__(a,b,c) print("init run") class A(metaclass=Meta): pass print(A)
单例设计模式:
使用原因:单例是为了节省资源,当一个类的所有对象属性全部相同时,那这时候就没有必要创建多个对象了
class meta(type): def __call__(self, *args, **kwargs): if hasattr(self, "obj"): return getattr(self, "obj") obj = super().__call__(*args, **kwargs) self.obj = obj print('创建了一个....') return obj class Student(metaclass=meta): def __init__(self, name): self.name = name s1 = Student('william') s2 = Student('william') s3 = Student('william') s4 = Student('william')