day 27-1 反射、内置方法、元类
反射
反射:通过字符串来映射到对象的属性
class people(): def __init__(self, name, age): self.name = name self.age = age def talk(self): print('name:%s,age:%s' % (self.name, self.age)) p = people('ysg', 21) # 判断 对象 中是否存在该属性,实际判断的是 p.__dict__ ['name'] print(hasattr(p, 'name')) # 结果:true # 取到 'name' 中的值 print(getattr(p, 'name', none)) # 结果:ysg print(getattr(p, 'names', none)) # 结果:none print(getattr(p, 'talk', none)) # <bound method people.talk of <__main__.people object at 0x0000020edf705278>> # 修改 'name' 中的值 setattr(p, 'name', 'ysging') # p.name = 'ysging' print(p.name) # 结果:ysging # 删除 'name' 对象 delattr(p, 'age') # del p.age print(p.__dict__) # 结果:{'name': 'ysging'}
有这样的需求:希望通过用户的输入内容来调用方法
例子
class people(): def __init__(self, name, age): self.name = name self.age = age def run(self): while 1: val = input('>>>') if hasattr(self, val): func = getattr(self, val, none) func() def talk(self): print('name:%s,age:%s' % (self.name, self.age)) p = people('ysg', 21) p.run() # 结果 # >>>talk # name:ysg,age:21
反射的好处:
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
好处二:动态导入模块(基于反射当前模块成员)
内置方法
isinstance(obj,cls) 检查是否 obj 是否是类 cls 的对象
class foo(): pass obj = foo() g = 123 print(isinstance(obj, foo)) # true print(isinstance(g, foo)) # false
issubclass(sub, super) 检查 sub 类是否是 super 类的派生类
class foo(): pass class a(foo): pass class b(): pass print(issubclass(a, foo)) # true print(issubclass(b, foo)) # false
item 系列:把对象做成像字典的类型
class foo(): def __init__(self, name): self.name = name def __getitem__(self, item): print('getitem...') return self.__dict__.get(item) def __setitem__(self, key, value): print('setitem...') print(key,value) # name ysging self.__dict__[key] = value def __delitem__(self, key): del self.__dict__[key] f = foo('ysg') print(f.__dict__) # {'name': 'ysg'} # 取值 print(f['name']) # ysg # 设置 f['name'] = 'ysging' print(f.name) # ysging # 删除 del f['name'] print(f.__dict__) # {}
__str__
一般情况下打印出为内存地址
class people(): def __init__(self, name, age): self.name = name self.age = age p = people('ysg', 22) print(p) # <__main__.people object at 0x000002c168d952e8>
使用 __str__ 后,打印结果可以自定义
class people(): def __init__(self, name, age): self.name = name self.age = age def __str__(self): return '<name:%s,age:%s>' % (self.name, self.age) p = people('ysg', 22) print(p) # <name:ysg,age:22>
__del__:如果在类内部定义了一个 __del__ 方法,则会在对象被删除的时候先自动触发这个方法,再把对象删掉
python只会回收对象本身的资源,不会回收与对象相关的数据
class open(): def __init__(self,file): print('open file...') self.file = file def __del__(self): print('回收与对象相关的资源:self.close()') #这里可以写上与对象相关的数据,如:操作系统中的资源 f = open('config.py') print('-------main-------')
析构方法,当对象在内存中被释放时,自动触发执行。
注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__
典型的应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源