day25
面向对象高级
一、isinstance and issubclass:
1、isinstance() 判断一个对象是不是一个类的实例化对象;
2、issubclass 判断一个类是不是另一个类的子类。
class People(object): pass class Student(People): pass stu = Student() isinstance() 判断一个对象是不是一个类的实例化对象 print(isinstance(stu, Student)) #True print(isinstance(stu, People)) #True print(isinstance(stu, object)) #True print(isinstance(stu, int)) #False issubclass 判断一个类是不是另一个类的子类 print(issubclass(Student, People)) #True
二、反射
1、什么是反射:程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。
2、反射提供的四种方法:
a、hasattr 是否存在某个属性
b、getattr 获取某个属性的值
c、setattr 设置某个属性的值
d、delattr 删除某个属性
注:以上的四个方法都是通过字符串来操作属性
class Student: def __init__(self,name,sex,age): self.name = name self.age = age self.sex = sex def study(self): print("学生正在学习...") stu = Student("egon","woman",38) # # print(stu.name) # stu.name = "gogon" # 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解释器无法自动完成的清理操作,已达到释放内存的效果。
# 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
1、作用:帮助解析字符串形式的python代码,并且将得到的名称存储到指定的名称空间中,Python解释器的内部也是通过调用它来执行代码的。
需要传入三个参数:
参数一:需要一个字符串对象 表示需要被执行的python语句;
参数二:是一个字典 表示全局名称空间;
参数三:也是一个字典 表示局部名称空间。
globalsdic = {} #相当于是python内置域 localsdic = {} #相当于前面提到的全局域 exec(""" aaaaaaaaaaaaaaaaaaaa = 1 bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2 def func1(): print("我是func1") """,globalsdic,localsdic) # 如果同时制定了 全局和局部 则 会字符串中包含名称 解析后存到局部中 # print(globalsdic) print(localsdic) localsdic["func1"]()
六、元类
1、元类用于产生类的类,type就是元类,所有的自定义类都是通过type实例化得来的。
2、类也是一个对象,可以通过使用type发现,类就是type类型的实例(对象),因此我们也可以自己调用type来实例化产生一个类。
#通过调用type来实例化一个类 classname = "student" student = type(classname, (object,),{}) print(student) print(student.__dict__) p1 = student() class Test(object): #Test = type("Test",(object,),{}) 等价 pass
总结:1、类是由type实例化产生的;
2、我们可以使用type来实例化出来一个类;
3、一个类是由类名字、类的父类元组和类的名称空间三个部分组成。
七、__ call__
在对象被调用时执行
自定义元类的目的:
1、可以通过__ call__来控制对象的创建过程:
#用__call__来控制对象的创建过程 class MyMeta(type): def __call__(self,*args,**kwargs): print("Meta call run!") obj = object.__new__(self) #创建一个空对象 self.__init__(obj,*args,**kwargs) #调用初始化函数 return obj #得到一个完整的对象 class People(metaclass = MyMeta): def __init__(self,name,age): self.name = name self.age = age def __call__(self): print("call run!") #调用Person这个对象时 执行的是 Person的类(MyMeta)中__call__ 方法 p = Person("张三疯",80) print(p) # 当调用对象时 会执行该对象所属类中的__call__方法 # p() print(p.name) print(p.age)
2、可以控制类的创建过程,(__ init__):
class MyMeta(type): def __init__(self,class_name,bases,namespace): print(self.__dic__) if not class_name.istitle: raise TypeError("类名首字母必须大写。。") if not self.__doc__: raise TypeError("类中必须要有文档注释。。。") class Student(metaclass = MyMeta): """ 这是文档注释 """ def __init__(self,name,age): self.name = name self.age = age
总结:
1、控制类的创建过程:
a、创建一个元类(需要继承type);
b、覆盖__ init__方法,该方法会将新建的类对象,类名,父类元组,名称空间一同传入;
c、对于需要被控制的类,需要在类名后面指定metaclass为上面的元类。
2、控制类实例化对象的过程
a、创建一个元类(需要继承type);
b、覆盖__ call__方法,会将正在实例化对象的类、调用类时传入的参数一同传入;
c、在__ call__方法中,必须要先编写模板代码;
1、创建空对象; 2、调用类的__ init__方法来初始化这个空对象; 3、返回该对象。
d、加入你需要控制的逻辑 。
八、单例
1、什么是单例:如果一个类只有一个实例,那么该类称之为单例
# 单例的实现 class MyMeta(type): obj = None def __call__(self, *args, **kwargs): if not MyMeta.obj: MyMeta.obj = object.__new__(self) self.__init__(MyMeta.obj, *args, **kwargs) return MyMeta.obj class Printer(metaclass=MyMeta): obj = None def __init__(self, name, brand, type): self.name = name self.brand = brand self.type = type @classmethod def get_printer(cls): if not cls.obj: cls.obj = cls("et202","aideli","2018") return cls.obj def printing(self): print("%s is printing!"%self.name) p = Printer.get_printer() print(p) p = Printer.get_printer() print(p) p = Printer.get_printer() print(p) p = Printer("et202","aideli","2018") print(p) #result: #<__main__.Printer object at 0x0000000002528E80> #<__main__.Printer object at 0x0000000002528E80> #<__main__.Printer object at 0x0000000002528E80> #<__main__.Printer object at 0x0000000002528E80>