面向对象之 —— isinstance、issubclass、反射、__str__、析构
一、isinstance\issubclass方法
isinstance(obj,cls):判断某个对象是不是某个类的实例
issubclass(sub,super):判断sub类是不是 super类子类/派生类 (所有类都是object的子类或子子类)
class Person: pass class Student(Person): pass stu = Student() print(type(1) == type(1)) # True print(isinstance(stu,Student)) # True print(issubclass(Student,Person)) # True
返回值都为bool类型
二、反射:对象具备修正错误的能力
程序可以访问、检测和修改它本身状态或行为的一种能力(自省),通过字符串来操作属性
- hasattr: (查看)是否存在某个属性
- getattr: 获取某个属性的值
- setattr: 设置某个属性的值
- delattr: 删除某个属性
class BlackMedium: feature='Ugly' def __init__(self,name,addr): self.name=name self.addr=addr def sell_house(self): print('%s 黑中介卖房子啦' %self.name)
def rent_house(self): print('%s 黑中介租房子啦' %self.name) b1=BlackMedium('万成置地','回龙观天露园') #检测是否含有某属性 print(hasattr(b1,'name')) print(hasattr(b1,'sell_house')) #获取属性 n=getattr(b1,'name') print(n) func=getattr(b1,'rent_house') func() # getattr(b1,'aaaaaaaa') #报错 print(getattr(b1,'aaaaaaaa','不存在啊')) #设置属性 setattr(b1,'sb',True) setattr(b1,'show_name',lambda self:self.name+'sb') print(b1.__dict__) print(b1.show_name(b1)) #删除属性 delattr(b1,'addr') delattr(b1,'show_name') delattr(b1,'show_name111')#不存在,则报错 print(b1.__dict__)
反射当前模块成员
#!/usr/bin/env python # -*- coding:utf-8 -*- import sys def s1(): print 's1' def s2(): print 's2' this_module = sys.modules[__name__] hasattr(this_module, 's1') getattr(this_module, 's2')
需要编写一个CMD工具 这个工具可以支持两个命令 dir ,tasklist
class CMD: def dir(self): print("列出当前文件夹目录....") def tasklist(self): print("查看任务列表.....") cmd = CMD() res = input("请输入指令:").strip() if hasattr(cmd,res): func = getattr(cmd,res) print(func) func() else: print("输入的指令不正确....")
优点:可以事先定义好接口,接口只有在被完成后才会真正执行,即可以事先把主要逻辑写好(只定义接口),然后后期去实现接口的功能。可以动态导入模块(基于反射当前模块成员)
注:前后带杠杠的都是特殊的内置函数(魔法方法),会在某些时机自动执行,一般情况我们不应该直接调用他们。要是实在想写一个同名的方法,可以写为_class模式(单下划线可防重名)。
三、__str__方法
当我们需要自定义打印显示内容时 就需要实现__str__方法,将对象转换成字符串时会自动执行,打印该对象时也会自动执行。
该方法必须返回一个字符串 返回的是什么 打印出来就是什么
class Test: def __init__(self,name): self.name = name def __str__(self): print("str run....") return self.name t = Test("haha") print(str(t)) # str run.... haha
改变对象的字符串显示:
- __str__:不能在交互式环境显示
- __repr__:交互模式在打印时其实是调用了__repe__,其输出结果面向的是解释器
自定制格式化字符串:__format__
四、__del__方法
解释器提醒即将把对象从内存中删除
将对象从内存中删除时会自动执行。程序员手动(调用__del__)删除这个对象也会自动执行
当使用python打开了一个不属于python管理的数据,因python解释器无法操作系统内存,故python解释器运行结束后,文件依然处于打开状态,此时就需要使用__del__关闭系统资源。简而言之,就是在程序运行结束时进行清理操作(如关闭文件资源)。
__del__也称之为析构函数,即分析构造,并拆除这个对象
class TextFile: def __init__(self,filepath,mode="rt",encoding="utf-8"): self.file = open(filepath,mode=mode,encoding=encoding) def read(self): return self.file.read() def write(self,text): self.file.write(text) # 该方法其实就是一个通知性质 仅仅是告诉程序员 对象即将被删除 def __del__(self): # 在这里关闭系统的文件 妥妥的 self.file.close() tf = TextFile("2.今日内容.txt") print(tf.read()) # tf.file.close() 不需要手动关闭了 在对象删除时会自动关闭 tf.read()
exec 执行字符串类型的python代码,用于执行文档内部程序
exec(execute):执行,解析执行字符串类型的python代码,并且将得到的名称存储到指定的名称空间,解释器内部也是调用它来执行代码的
# 参数一 需要一个字符串对象 表示需要被执行的python语句 # 参数二 是一个字典 表示全局名称空间 # 参数三 也是一个字典 表示局部名称空间(通常都是局部) globalsdic = {} localsdic = {} exec(""" aaaaaaaaaaa = 1 bbbbbbbbbbb = 2 def func1(): print("func1") """,globalsdic,localsdic) # 如果同时制定全局和局部 则会将字符串中包含的名称 解析后存到局部中 # print(globalsdic) print(localsdic) localsdic["func1"]() # 如果只传了一个传参数 则将字符串中包含名称 解析后存到全局中
典型的应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中。
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源。这与文件处理是一个道理。
f=open('a.txt') #做了两件事,在用户空间拿到一个f变量,在操作系统内核空间打开一个文件 del f #只回收用户空间的f,操作系统的文件还处于打开状态 #所以我们应该在del f之前保证f.close()执行,即便是没有del,程序执行完毕也会自动del清理资源,于是文件操作的正确用法应该是 f=open('a.txt') 读写... f.close() 很多情况下大家都容易忽略f.close,这就用到了with上下文管理