今天主要的内容由getattr、hasattr、delattr、setattr引出反射问题,随后又补充了__import__、importlib,随后衍生了包装(利用类的派生)、授权(__getattr__)
一、反射的引入
# 关于反射,涉及四个hasattr、setattr、delattr、getattr # 反射是供类和对象进行使用的 # 首先还是定义一个演示类 # class Test: # '定义了一个用于演示的类' # country = 'China' # def __init__(self,name): # self.name = name # # def niubi(self): # print('%s是一个很牛逼的测试类') # 首先是关于hasattr,用于检测类中是否存在一个属性,返回bool值 # print(hasattr(Test,'niubi')) # True # print(hasattr(Test,'123')) # False # 上面这种是直接针对类进行使用的,下面再看看实例化对象 # t1 = Test('alex') # print(hasattr(t1,'niubi')) # True # print(hasattr(t1,'country')) # True # hasattr 以及后面即将演示的函数都要求后面属性名是一个字符串的形式 # delattr 删除属性 # print(t1.__dict__) #{'name': 'alex'} # delattr(t1,'name') # print(t1.__dict__) #{} # 记住实例化的对象的字典里面没有类的方法 # print(Test.__dict__) # print(delattr(Test,'niubi')) # print(Test.__dict__) #此时类的方法就被删除掉了 # 关于getattr的使用,获取属性对应的值 # t1 = Test('xiaoy') # print(getattr(t1,'country')) #China # print(getattr(Test,'niubi')) #<function Test.niubi at 0x00000178A7DE4488> # 返回的是一个方法的地址 # print(getattr(Test,'niubi')) #<function Test.niubi at 0x00000178A7DE4488> # getattr和delattr 的操作范围记得区分哦 # delattr针对的是.__dict__对应的字典 # 关于setattr的使用,输入对应的键值对,其实在底层就是实例化的过程 # print(t1.__dict__) # {'name': 'xiaoy'} # setattr(t1,'age',18) # print(t1.__dict__) # {'name': 'xiaoy', 'age': 18} # 关于他们四个的直接作用是这些 # 下面是关于__getattr__ __setattr__ __delattr__ # __getattr__ 找不到调用的类时候会执行这个函数 # __setattr__ 导入item的时候会执行 # __delattr__ 删除字典内容的时候会执行 class Test: '定义了一个用于演示的类' country = 'China' def __init__(self,name,age): self.name = name self.age = age def niubi(self): print('%s是一个很牛逼的测试类') def __getattr__(self, item): print('getattr执行了') def __delattr__(self, item): # print('delattr执行了') return (self.__dict__.pop(item)) def __setattr__(self, key, value): print('setattr开始执行了') print('__setattr__执行') # # self.key=value # 这样会陷入持续的递归当中 return self.__dict__[key]=value t1 = Test('alex',19) # 我们执行一个不存在的函数 # t1.none() # print(t1.__dict__) #{'age': 19, 'name': 'alex'} # del t1.name #delattr执行了 # print(t1.__dict__) #{'age': 19, 'name': 'alex'} # 为啥这个地方没能删除成功呢,因为你修改了底层原有的代码 # 我们重新修改一下 # print(t1.__dict__) #{'age': 19, 'name': 'alex'} # del t1.name #delattr执行了 # print(t1.__dict__) #{'age': 19} # 这个时候就正常执行了del模式 # del对应的就是__delattr__ # setattr t1.y=10 t1.x=3 # 设置属性的时候会触发——setattr——— #我们修改了他的底层,就没办法保证正常的执行了
二、动态导入
module_t=__import__('m1.t') # 这种导入方法即使你的后面跟着很多他依然只会导入最开始的 print(module_t) # module_t.t.test1() # from m1.t import * # from m1.t import test1,_test2 # # test1() # _test2() import importlib m=importlib.import_module('m1.t') # 导入到那一层就可以使用那一层 print(m) m.test1() m._test2()
三、包装,这个还是蛮神奇的,通过继承派生,我们可以在原生类上加上自己想要的功能
class List(list): def append(self, p_object): if type(p_object) is str: # self.append(p_object) super().append(p_object) else: print('只能添加字符串类型') def show_midlle(self): mid_index=int(len(self)/2) return self[mid_index] # l2=list('hell oworld') # print(l2,type(l2)) l1=List('helloworld') # print(l1,type(l1)) # print(l1.show_midlle()) l1.append(1111111111111111111111) l1.append('SB') print(l1)
四、授权,我们刚才是通过继承实现了包装功能,现在就要使用牛逼的__getattr__
import time class FileHandle: def __init__(self,filename,mode='r',encoding='utf-8'): # self.filename=filename self.file=open(filename,mode,encoding=encoding) self.mode=mode self.encoding=encoding def write(self,line): print('------------>',line) t=time.strftime('%Y-%m-%d %X') self.file.write('%s %s' %(t,line)) def __getattr__(self, item): # print(item,type(item)) # self.file.read return getattr(self.file,item) f1=FileHandle('a.txt','w+') # print(f1.file) # print(f1.__dict__) # print('==>',f1.read) #触发__getattr__ # print(f1.write) f1.write('1111111111111111 ') f1.write('cpu负载过高 ') f1.write('内存剩余不足 ') f1.write('硬盘剩余不足 ') # f1.seek(0) # print('--->',f1.read())
三、四部分没有增加相关解释逻辑,因为今天太晚了,明天我会增加上的,各位敬请期待