对于面向对象之反射,我的理解是你通过输入的方式给出一个指令,我不需要知道你给出的是哪个对象,其中的指令有哪些,我只要管自己输入要执行的指令,有我就执行,没有我就返回指令不存在的提示。
class WinCmd(object): def ls(self): print('windows系统正在执行ls命令') def dir(self): print('windows系统正在执行dir命令') def cd(self): print('windows系统正在执行cd命令') class LinuxCmd(object): def ls(self): print('Linux系统正在执行ls命令') def dir(self): print('Linux系统正在执行dir命令') def cd(self): print('Linux系统正在执行cd命令') obj = WinCmd() obj1 = LinuxCmd() '''反射提供了一种不需要代码的前提下,操作数据和功能''' def run(obj): while True: cmd = input('请输入您的指令>>>:') if hasattr(obj,cmd): func_name = getattr(obj, cmd) func_name() else: print('cmd command not found') run(obj1) run(obj)
面向对象的双下方法被一些人称为魔法方法,因为一些面向对象双下方法在达到某个条件的时候会自动触发,不需要手动调用
# __str__ class person(object): def __init__(self, name): self.name = name def __str__(self): print('__str__执行') return '打印时执行__str__' obj1 = person('king') print(obj1) print(person) ''' 在对象被执行打印(print、前端展示)操作的时候自动触发 该方法必须返回字符串类型的数据,不然会报错 主要用于精准的描述对象 ''' # __del__ class person(object): def __init__(self, name): self.name = name def __del__(self): print(self.name) obj1 = person('king') # 执行完成代码为被动 # print(obj1) # print('哈哈') # 主动 print(obj1) del obj1 print('哈哈') ''' 对象被执行(被动、主动)删除操作之后自动执行 被动删除:python解释器会在程序执行完成之后,自动删除内容 主动删除:使用del等删除的关键字手动删除 ''' # __getattr__ class person(object): def __init__(self, name): self.name = name def __getattr__(self, item): print(f'{item}对象查找不存在') obj1 = person('king') print(obj1.age) # None,__getattr__的执行在这个结果出现之前 ''' 对象查找(使用)不存在的名字的时候自动触发 ''' # __setattr__ # 主要用于给对象添加属性用的,当对象执行添加属性操作的时候自动触发 >>> obj.变量名=变量值 class person(object): def __init__(self, name): self.name = name def __setattr__(self, key, value): print('执行了__setattr__') super().__setattr__(key, value) ''' 当你对__setattr__方法进行操作添加的时候要记得继续再继承一下父类的方法__setattr__不然你的属性添加不到对象的名称空间中 ''' obj1 = person('king') obj1.age = 18 # print(obj1.age) print(obj1.__dict__) # __call__ class person(object): def __init__(self, name): self.name = name def __call__(self, *args, *kwargs): print('hahaha', args, kwargs) return 'sdaadssd' obj1 = person('king') obj1(1) ''' 用于对象加括号调用的时候自动触发,如果想接受实参,加上形参即可 ''' # __enter__ class person(object): def __init__(self, name): self.name = name def __enter__(self): print('执行__enter__') def __exit__(self, exc_type, exc_val, exc_tb): # 一定要加上后面三个参数,在看不到的地方自动传入了四个参数 print('执行__exit__', exc_type, exc_val, exc_tb) # 执行__exit__ None None None obj1 = person('king') with obj1 as f: # with程序开始,自动执行__enter__ print('123') # with程序结束,自动执行__exit__ print('321') ''' __enter__和__exit__必需配合使用 ''' # __getattribute__ class person(object): def __init__(self, name): self.name = name def __getattribute__(self, item): print(f'{item}',item) obj1 = person('king') print(obj1.__dict__) # None 只要一看到对象查找名字(调用数据),就运行__getattribute__ print(obj1.age) # None print(obj1.name) # None ''' 只要对象查找名字无论名字是否存在都会执行该方法 如果类中有__getattribute__方法 那么就不会去执行__getattr__方法 用了这个方法,就算有这个属性,print打印的结果也是None '''
# 让字典具备据点符查找值的功能 # 1.定义一个类继承字典 class MyDict(dict): # 做到可以句点符取值 def __getattr__(self, item): return self.get(item) # 做到句点符赋值 def __setattr__(self, key, value): self[key] = value # 对象名称空间中是正常的属性=属性值,而字典中是键值队的形式,因此赋值方式要更改一下 '''对于这个题目要做到区分是名称空间的名字还是数据k:v键值对''' obj = MyDict({'name': 'jason', 'age': 18}) # 1.具备句点符取v # print(obj.name) obj.pwd = 123 # 相当于 正常字典的obj['gender'] = 'male' '''给字典名称空间添加名字,不是数据k:v''' print(obj) 2.补全下列代码 使其运行不报错 # 补全下列代码 使其运行不报错 class Context: def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): pass def do_something(self): pass with Context() as ctx: ctx.do_something() ''' 对于with 对象 as 变量名: 来说对象所属的类中一定要有双下enter和双下exit 对于对象内容所变成的do_something来说,对象内要有do_something方法 '''
# 元类 即产生类的类 class MyClass(object): pass obj = MyClass() print(type(obj)) # <class '__main__.MyClass'> type查看的其实是当前对象所属的类名称 print(type(MyClass)) # <class 'type'> class Student: pass print(type(Student)) # <class 'type'> class Teacher(MyClass): pass print(type(Teacher)) # <class 'type'> '''type就是所有类默认的元类'''
1.class关键字 class C1(object): pass print(C1) # <class '__main__.C1'> 2.type元类 type(类名,父类,类的名称空间) res = type('C1', (), {}) print(res) # <class '__main__.C1'> ''' 学习元类的目的 元类能够控制类的创建 也就意味着我们可以高度定制类的行为 eg:掌握了物品的生产过程 就可以在过程中做任何的额外操作 比如:要求类的名字必须首字母大写 思考在哪里编写定制化代码 类的产生过程目前还比较懵 元类里面的__init__方法 对象的产生过程呢 类里面的__init__方法 方法:由已知推未知 '''
'''元类是不能通过继承的方式直接指定的''' 通过关键字参数metaclass修改该类的元类,C1的创建受自己元类的影响 class C1(metaclass=MyTypeClass): pass class MyTypeClass(type): # 元类用来定制类的行为(样式) def __init__(cls, cls_name, cls_bases, cls_dict): # 必须写明4个形参,因为默认传入4个实参 # print(cls, cls_name, cls_bases, cls_dict) if not cls_name.istitle(): raise Exception("类名的首字母必须大写 你个sd") super().__init__(cls_name) class C1(metaclass=MyTypeClass): school = "清华大学" class a(metaclass=MyTypeClass): school = '清华大学'
1.回想__call__方法 对象加括号会自动执行产生该对象的类里面的__call__,并且该方法返回什么对象加括号就会得到什么 推导:类加括号会执行元类的里面的__call__该方法返回什么其实类加括号就会得到什么 """类里面的__init__方法和元类里面的__call__方法执行的先后顺序""" class MyTypeClass(type): def __call__(self, *args, **kwargs): print('__call__ run') print(args, kwargs) super(MyTypeClass, self).__call__(*args, **kwargs) class MyClass(metaclass=MyTypeClass): def __init__(self, name): print('__init__') self.name = name obj = MyClass('jason') # call在init前运行 # 定制对象的产生过程 class MyTypeClass(type): def __call__(self, *args, **kwargs): if args: # 若args有值表示输入的不是关键字参数 raise Exception("必须全部采用关键字参数") super().__call__(*args, **kwargs) class MyClass(metaclass=MyTypeClass): def __init__(self, name): self.name = name '''只要为了展示,传入的值目前拿不出来''' '''强制规定:类在实例化产生对象的时候 对象的独有数据必须采用关键字参数''' obj2 = MyClass(name='jason') # 关键字参数是放在kwargs里的 print(type(obj2)) ''' 如果你想高度定制类的产生过程 那么编写元类里面的__init__方法 如果你想高度定制对象的产生过程 那么编写元类里面的__call__方法 '''
__new__用于产生空对象(类) 骨架 __init__用于实例化对象(类) 血肉 class MyTypeClass(type): # def __new__(cls, *args, **kwargs): # print('__new__ run') # return super().__new__(cls, *args, **kwargs) # # def __init__(cls,cls_name, cls_bases, cls_dict): # print('__init__ run') # super().__init__(cls_name, cls_bases, cls_dict) def __call__(cls, *args, **kwargs): # 1.产生一个空对象 obj = object.__new__(cls, *args, **kwargs) # 2.调用init方法实例化 return obj class MyClass(metaclass=MyTypeClass): def __init__(self, name): self.name = name obj = MyClass('jason') print(obj) """ 注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层 如果是在元类的__new__里面 可以直接调用 class Meta(type): def __new__(cls, *args, **kwargs): obj = type.__new__(cls,*args,**kwargs) return obj 如果是在元类的__call__里面 需要间接调用 class Mate(type): def __call__(self, *args, **kwargs): obj = object.__new__(self) # 创建一个空对象 self.__init__(obj,*args,**kwargs) # 让对象去初始化 return obj """