OOP之反射和元类
-
反射(reflection)
-
定义:指的是对象可以通过代码来增删改查其中的属性以及方法
-
通过四个函数来实现这个功能,它们分别是hasattr()(查),getattr()(改),setattr()(增),delattr()(删)
-
class Player: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def playoff(self): print('他能在季后赛砍下30分') kobe = Player('kobe bryant',42,'male') print(hasattr(kobe,'name')) # 判断kobe对象中有无'name'的属性或者方法 print(getattr(kobe,'name')) # 从kobe对象中取出name属性 print(getattr(kobe,'career','DDD')) # 如果对象中没有指定的属性,则返回最后一个参数即默认值可以是字符串也可以是布尔值 getattr(kobe,'playoff')() # 其中也可以从对象中取出方法加括号的方式调用 setattr(kobe,'team','lakers') # 在对象中添加属性,对象名,属性名,属性的值 delattr(kobe,'team') # 删除对象中的team属性 print(kobe.team) # 报错AttributeError: 'Player' object has no attribute 'team'
-
为什么要引入反射概念
- 一方面是不用通过__dict__方法查找对象中的属性以及方法名,极大地简化了操作属性的步骤和程序
- 另一方面也是最重要的一点是,如果这个对象不是自己写的话,,我就必须判断这个对象是否满足的要求,也就是否符合我需要的属性和方法
-
框架代码
-
from lib import settings # 加载输出文件 import importlib # 导入模块的模块文件 def run(insert_thing): # 我要知道这个对象是插件中的哪个类的对象 while True: cmd = input('请输入您想要执行的功能>>>:') if cmd == 'exit': print('退出程序') break if hasattr(insert_thing,cmd): func = getattr(insert_thing,cmd) func() else: print('您输入的功能不存在') # 将路径导出 path = settings.CLASS_PATH # 拿出插件模块名称和类名称 module_name, class_name = path.rsplit('.',1) # 导入插件模块 module = importlib.import_module(module_name) # 取出类名称 cls = getattr(module,class_name) print(cls) obj = cls() # 运行 run(obj)
-
插件模块代码
-
class WinCMD: def cd(self): print("wincmd 切换目录....") def delete(self): print("wincmd 要不要删库跑路?") def dir(self): print("wincmd 列出所有文件....") class LinuxCMD: def cd(self): print("Linuxcmd 切换目录....") def rm(self): print("Linuxcmd 要不要删库跑路?") def ls(self): print("Linuxcmd 列出所有文件....")
CLASS_PATH = 'inserthings.WinCMD' 这个是配置文件中的代码
-
元类(metaclass)
-
定义:创建类的类,其不光能定义对象的行为还能够定义类的行为。说白了类就是元类的实例化,任何类都是type类的实例化。
-
class Person: pass p = Person() print(type(p)) # <class '__main__.Person'> print(type(Person)) # <class 'type'> # Person类是通过type类实例化产生的
-
似乎元类和继承有着相似的地方,但是它们是完全不同的,元类是类的实例化,而继承则是类与类之间的联系,子类可以使用父类中的属性和方法,元类则是产生与被产生(类与对象)的关系,用来限制类的创建。
-
如何控制类对象的创建
-
__init__ 方法(创建类之后的调用)
-
""" 只要继承了type类,那么该类就是一个元类 """ class Type2(type): def __init__(self,cls_name,base,dict): super().__init__(cls_name,base,dict) print(cls_name,base,dict) if not cls_name.istitle(): print('你的类的首字母没有大写') class Instance(metaclass = Type2): # 为实例化的一个类指定了元类 pass class instance1(metaclass = Type2): # 输出你的类的首字母没有大写,起到了限制类的名字命名规范的效果 pass
-
控制类实例化对象的创建 __call__方法
-
当你调用类对象时会自动珍惜元类中的__call__方法 ,并将这个类本身作为第一个参数传入,以及后面的一堆参数,覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建并返回其返回值。
-
class Upper(type): def __call__(self,*args,**kwargs): new_args = [] for item in args: new_args.append(item.upper()) print(new_args) # ['KOBE', 'MALE'] return super().__call__(*new_args,**kwargs) class Student(metaclass = Upper): def __init__(self,name,gender): self.name = name self.gender = gender stu1 = Student('kobe','male') print(stu1.name) # 返回KOBE
-
控制类创建的__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)
-
单例设计模式
-
# 单例n元类 class Single(type): def __call__(self, *args, **kwargs): if hasattr(self,"obj"): #判断是否存在已经有的对象 return getattr(self,"obj") # 有就返回 obj = super().__call__(*args,**kwargs) # 没有则创建 print("new 了") self.obj = obj # 并存入类中 return obj class Student(metaclass=Single): def __init__(self,name): self.name = name