一、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
二、反射:对象具备修正错误的能力
程序可以访问、检测和修改它本身状态或行为的一种能力(自省),通过字符串来操作属性
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')
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("输入的指令不正确....")
优点:可以事先定义好接口,接口只有在被完成后才会真正执行,即可以事先把主要逻辑写好(只定义接口),然后后期去实现接口的功能。可以动态导入模块(基于反射当前模块成员)
前后带杠杠的都是特殊的内置函数 会在某些时机自动执行 一般情况我们不应该直接调用他们
__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__
自定制格式化字符串__format__
__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上下文管理
元类:用于产生类的类,type就是元类
所有的自定义类都是通过type实例化得来
创建模块的过程 1.创建一个空的名称空间 2.执行内部的代码 3.将得到的名字放到名称空间中 控制类的创建过程 1.创建一个元类 (需要继承type) 2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 , 可以利用这些信息在做处理 3.对于需要被控制的类 需要指定metaclass 为上面的元类 控制类实例化对象的过程 1.创建一个元类 (需要继承type) 2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来 3.在__call__方法中 必须要先编写模板代码 3.1创建空对象 3.2调用类的__init__方法来初始化这个空对象 3.3返回该对象 4.加入你需要控制的逻辑
创建模块的过程 1.创建一个空的名称空间 2.执行内部的代码 3.将得到的名字放到名称空间中 控制类的创建过程 1.创建一个元类 (需要继承type) 2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 , 可以利用这些信息在做处理 3.对于需要被控制的类 需要指定metaclass 为上面的元类 控制类实例化对象的过程 1.创建一个元类 (需要继承type) 2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来 3.在__call__方法中 必须要先编写模板代码 3.1创建空对象 3.2调用类的__init__方法来初始化这个空对象 3.3返回该对象 4.加入你需要控制的逻辑
类的三个组成部分:类名 父类们 名称空间
# myclass 包含的代码 code = """ name = "张三" age = 18 def hello(self): print("hello %s" % self.name) """ class_name = "MyClass" # 类的名字 base_classes = (object,) # 类的的父类们 namespace = {} # 类的名称空间 exec(code,{},namespace) res = type(class_name,base_classes,namespace) print(Student) print(res.name) print(res.age) print(res.hello) # 1.类是由type实例化产生的 # 2.我们可以使用type来产生一个类 # 3.一个类是由 类名字 类的父类元祖 类的名称空间 三个部分组成 class Test(object): #Test = type("Test",(object,),{}) pass
元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象
1. 通过元类来控制类的创建过程 实现 类中必须包含 __doc__ 类名必须是大写开头。
要控制类的创建过程 只要找到类所属的类 中的__init__即可
2. 通过元类来实现一个单例
单例模式:一种设计模式(套路)
单个实例:一个类如果只有一个实例 那么该类称之为单例
为什么需要单例:通过这种方法,可以保证只有一个对象(以__call__控制实例化过程,保证每一次调用都返回一个实例)
__call__方法:对象后面加括号,触发执行。
自定义元类 的目的
1.可以通过__call__ 来控制对象的创建过程
2.可用控制类的创建过程
# 自定义一个元类 元类也是一个类 但是需要继承type class MyMeta(type): def __call__(self, *args, **kwargs): # self 表示要创建对象的那个类(Person) *args是调用Person类时传入的参数 print("MyMte中的 call run'") print(self,*args,**kwargs) # 下面的三步是固定写法 一个模板 只要你需要控制对象的创建过程 就应该先把模板写出来 # 1.创建空对象 obj = object.__new__(self) # 2.调用初始化方法 self.__init__(obj,*args,**kwargs) # self.__init__(obj) # 3.得到一个完整的对象 return obj class Person(metaclass=MyMeta): # 修改Person类的元类为MyMeta def __init__(self,name,age): self.name = name self.age = age def __call__(self, *args, **kwargs): print("call run...") p = Person("王二狗",66) # 调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法 print(p) # 当调用对象时 会执行该对象所属类中的__call__方法 # p() 可以这样调用哟 print(p.name) print(p.age)
注意:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()