isinstance() 判断某个对象是不是某个类的实例
issubclass() 是不是字类
# 判断某个对象是不是某个类的实例 # isinstance() class Person: # pass class Student(Person): pass stu = Student() #判断 两个对象是不是同一个类型 print(type(1) == type(1)) # 判断stu对象是不是Student类的实例 print(isinstance(stu,Student)) # 是不是子类 # issubclass() # 判断一个类是不是 另一个类子类 (所有类都是object的子类或子子类) print(issubclass(Student,Person))
反射 其实说的实反省
简单的说 就是 对象要具备一种修正错误的能力
hasattr 是否存在某个属性
getattr 获取某个属性的值
setattr 设置某个属性的值
delattr 删除某个属性
这几方法有一个共同点 都是通过字符串来操作属性
你可以理解为 通过字符串来操作属性 就叫做反省
class Student: def __init__(self,name,sex,age): self.name = name self.age = age self.sex = sex def study(self): print("学生正在学习...") stu = Student("矮根","woman",38) # # print(stu.name) # # stu.name = "高根" # # del stu.name # 当你获取到一个对象 但是并不清楚搞对象的内部细节时 就需要使用反射了 def test(obj): if hasattr(obj,"name"): print(getattr(obj,"name","没有name属性")) test(stu) setattr(stu,"school","beijing") delattr(stu,"school") print(getattr(stu,"school","没有学校属性")) delattr(stu,"age") print(stu.age)
""" 如果在编写代码期间 就能明确知道我要访问的属性 没有必要使用反射 如果在编写代码期间 无法明确知道我要访问的属性 这时就应该使用反射 """ # class Student: # def study(self): # print("学习中....") # # # stu = Student() # # res = getattr(stu,"study",None) # # print(res) # # def eat(self): # print("正在吃饭...") # # # 可以通过反射的方式为对象增加一个方法 但是注意 这样增加的方法就是一个普通函数 不会自动传值 # setattr(stu,"eat",eat) # # print(getattr(stu,"eat",None)) # 需要编写一个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("输入的指令不正确....")
""" __str__ 前后带杠杠的都是特殊的内置函数 会在某些时机自动执行 一般情况我们不应该直接调用他们 当我们需要自定义打印显示内容时 就需要实现__str__方法 该方法必须返回一个字符串 返回的是什么 打印出来就是什么 """ class Test: def __init__(self,name): self.name = name def __str__(self): print("str run....") return self.name t = Test("安米") print(int(1).__str__()) # print([1,2,3,5]) # print(t) # 在讲一个对象转换字符串时 本质就是在调用这个对象 __str__方法 print(str(t))
""" __del__ 当对象被从内存中删除时会自动执行 另一种情况时 程序员手动删除了这个对象 也会自动执行 什么时候使用它 在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作 但是有一种情况 我们使用python打开了一个不属于python管理的数据 比如打开了一个文件 这个文件一定是操作系统在打开 会占用系统内存 而python解释器无法操作系统内存的 所以 当你的python解释器运行结束后 文件依然处于打开状态 这时候就需要使用__del__来关闭系统资源 简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__ __del__也称之为 析构函数 分析构造 并拆除这个对象 """ # # class Student: # # def __del__(self): # print("对象被删除了....") # # # stu = Student() # # # 手动删除 立即执行__del__ # del stu # # import time # # time.sleep(5) 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 execute的缩写 表示执行的意思 其作用 是帮你解析执行python代码 并且将得到的名称 存储到制定的名称空间 解释器内部也是调用它来执行代码的 """ # 参数一 需要一个字符串对象 表示需要被执行的python语句 # 参数二 是一个字典 表示全局名称空间 # 参数三 也是一个字典 表示局部名称空间 globalsdic = {} localsdic = {} exec(""" aaaaaaaaaaaaaaaaaaaa = 1 bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2 def func1(): print("我是func1") """,globalsdic,localsdic) # 如果同时制定了 全局和局部 则 会字符串中包含名称 解析后存到局部中 # print(globalsdic) print(localsdic) localsdic["func1"]() # # 如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中 # exec(""" # aaaaaaaaaaaaaaaaaaaa = 1 # bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2 # # """,localsdic)
""" 一切皆对象 元类是指 用于产生类的类 type就是元类 所有的自定义类都是通过type实例化得来 """ #创建模块的过程 1.创建一个空的名称空间 2.执行内部的代码 3.将得到的名字放到名称空间中 # class也是一个对象 class Student(object): school = "北京大学!" def study(self): print("学习中...") # 使用type可以发现 类其实是type类型的实例(对象) print(type(Student)) # 我们可以自己调用type来实例化产生一个类 # 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
""" __call__ 调用的意思 在在对象被调用时 执行 函数 类 自定义元类 的目的 1.可以通过__call__ 来控制对象的创建过程 2.可用控制类的创建过程 """ # 自定义一个元类 元类也是一个类 但是需要继承type class MyMeta(type): # self 表示要创建对象的那个类(Person) *args是调用Person类时传入的参数 def __call__(self, *args, **kwargs): 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 # 修改Person类的元类为MyMeta class Person(metaclass=MyMeta): def __init__(self,name,age): self.name = name self.age = age def __call__(self, *args, **kwargs): print("call run...") #调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法 p = Person("张三疯",80) print(p) # 当调用对象时 会执行该对象所属类中的__call__方法 # p() print(p.name) print(p.age) # class People: # def __init__(self,name): # self.name = name # pass # # # p = People() # p.anme = 1
# 要控制类的创建过程 只要找到类所属的类 中的__init__即可 class MyMeta(type): # self 刚建出来的类 # 第二个 类的名字 # 第三个 类的父类们 元组 # 第四个 这个类传进来的名称空间 def __init__(self,class_name,bases,namespace): print("============================") #print(self.__dict__) # 我要控制 类的名字 必须 是大写开头 if not class_name.istitle(): print("类名 必须大写开头...... ") # 该代码是主动抛出异常 raise TypeError("类名 必须大写开头...... ") #要空类的创建 必须包含__doc__这个属性 if not self.__doc__: raise TypeError("类中必须有文档注释.....") pass class Student(metaclass=MyMeta): # Student = MyMeta("Student",(object,),{}) """ 这是文档注释 可以通过__doc__来获取 这是一个学生类 """ # 在类的__init__中可以控制该类对象的创建过程 def __init__(self,name): print("-----------------------") print(self.__dict__) self.name = name print(Student.__doc__) # 元类使用总结: """ 元类是用于创建类的类 学习元类是为了 能控制类的创建过程 以及 类实例化对象的过程 一. 控制类的创建过程 1.创建一个元类 (需要继承type) 2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 , 可以利用这些信息在做处理 3.对于需要被控制的类 需要指定metaclass 为上面的元类 二. 控制类实例化对象的过程 1.创建一个元类 (需要继承type) 2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来 3.在__call__方法中 必须要先编写模板代码 3.1创建空对象 3.2调用类的__init__方法来初始化这个空对象 3.3返回该对象 4.加入你需要控制的逻辑 类的三个组成部分 类名 父类们 名称空间 元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象 """
class MyMeta(type): obj = None def __call__(self, *args, **kwargs): if not self.obj: obj = object.__new__(self) self.__init__(obj,*args,**kwargs) self.obj = obj return self.obj #打印机类 class Printer(metaclass=MyMeta): """ 这是一个单例类 请不要直接实例化 使用get方法来获取实例 """ obj = None def __init__(self,name,brand,type): self.name = name self.brand = brand self.type = type def printing(self,text): print("正在打印 %s" % text) # 通过该方法来获取对象 可以保证只有一个对象 # 但是这还不够 因为 还是可以通过调用类产生新对象 # 就应该使用元类 来控制实例化的过程 __call__ # 在__call__ 中编写代码 保证每次调用call 都返回同一个实例 即可 # 以下三个对象 的数据完全相同 但是却 占用三分内存空间 # p1 = Printer("ES005","爱普生","彩色打印机") # p2 = Printer("ES005","爱普生","彩色打印机") # p3 = Printer("ES005","爱普生","彩色打印机") # 现在要处理问题就是 如何能够限制该类 只能实例化一个对象 p1 = Printer("ES005","爱普生","彩色打印机") p2 = Printer("ES007","爱普生","彩色打印机") print(p1) print(p2.name) # print(p1,p2,p3) # p1.printing("一本小说....")