一.isinstance和issubclass
1.isinstance():用来判断某个对象是不是某个类的实例。
print(isinstance([],list)) #判断这个[]是不是一个列表 True
2.issubclass():用来判断一个类是不是另一个类的子类。
print(list,object) #判断list这个类是不是object的子类 True
二.反射(自省)
简单的来说反射就是对象要具备一种修正错误的能力,或者说通过字符串来操作属性就是反射。
反射有以下几种方法:
1. hasattr 判断是否存在某个属性
2. getattr 获取某个属性的值
3. setattr 设置某个属性的值
4. delattr 删除某个属性
以上几种方法的共同点都是通过字符串来操作属性的。反射操作的都是对象__dict__中的内容。
class People: def __init__(self, name, age): self.name = name self.age = age p1 = People('wangke', 25) print(hasattr(p1, 'name')) # 判断p1是否存在name属性,存在返回True,不存在则返回False print(getattr(p1, 'aaa', None)) # 获取p1的name属性的值,如果没有该属性,则返回None setattr(p1, 'name', 'wk') # 设置name属性的值,如果存在name则修改原值,如果不存在name,则添加该属性 print(p1.name) delattr(p1,'name') # 删除name属性

# 需要编写一个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__方法
这是python解释器的内置函数,当我们需要自定义打印显示的内容时,就需要去实现__str__方法。此方法vixu返回一个字符串,打印的结果就是返回的结果。
class Student: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return 'name:%s,age:%s' % (self.name, self.age) # 自定义打印的结果 stu1 = Student('wangke', 25) print(stu1) # name:wangke,age:25
四.__del__方法
此方法在当对象被从内存中删除时,会自动执行,或者手动删除对象时,也会自动执行。该方法也称为析构函数(分析构造并拆除对象)。
什么时候使用__del__方法?
简单的来说就是当程序运行结束时,需要做一些清理的操作,就是用__del__方法。(在python中,有自动内存管理机制,所以 python自己创建的数据不需要我们做任何操作。但是有一种情况:我们使用python打开了一个不属于python管理的数据,比如:打开了一个文件,这个文件一定是操作系统在打开,会占用系统内存,而python解释器无法操作系统内存。所以当你的python解释器运行结束后,文件依然处于打开状态,这时候就需要使用__del__来关闭系统资源)
class File: def __init__(self, name, mode='rt', encoding='utf-8'): self.file = open(name, mode=mode, encoding=encoding) def read(self): self.file.read() def write(self, text): self.file.write(text) def __del__(self): # 程序运行完,通知系统需要进行删除操作 self.file.close() # 通知系统关闭文件 f1 = File('aaa') f2 = File('aaa', 'wt') f1.read() f2.write('1')
五.exec(execute)方法
exec作用时帮你解析执行python代码,并且将得到的名称,存储到指定的名称空间。它有三个参数:
参数一:需要一个字符串对象,表示需要被执行的python语句
参数二:一个字典,表示全局名称空间
参数三:一个字典,表示局部名称空间
如果三个参数同时存在,则会将字符串中包含的名称,解析后存到局部名称空间中。如果只有前俩个参数,则会存到全局名称空间中。
# 创建一个字符串对象 str1 = ''' a = 1 class Student: def __init(self, name, age, sex): self.name = name self.age = age self.sex = sex def learning(self): print('%s正在学习。。。' % (self.name)) ''' globals_dic = {} # 创建全局名称空间 locals_dic = {} # 创建局部名称空间 exec(str1, globals_dic, locals_dic) print(locals_dic) # {'a': 1, 'Student': <class 'Student'>} stu1 = locals_dic.get('Student')() print(stu1) # <Student object at 0x000002ABEE979908>
六.元类
元类指的是用于产生类的类,type就是元类。类也是一个对象,我们可以通过元类(type)来实例化产生一个类。
创建类的三要素:
1.类名,2.基类(元组的形式),3.类的名称空间
class_name = 'People' # 类名 class_bases = (object,) # 基类 class_dic = {} # 类的名称空间 str1 = ''' def foo(): import time print('hello') name = 'wangke' age = 25 time.sleep(2) print('name:%s age:%s' % (name,age)) ''' res = exec(str1, {}, class_dic) print(class_dic) # {'foo': <function foo at 0x000001DB604D2E18>} People = type(class_name, class_bases, class_dic) # 创建类
七.__call__方法
对象后面加括号,触发执行__call__方法。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()。
class Foo: def __init__(self): pass def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__ obj() # 执行 __call__

""" __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 My(type): def __call__(self, *args, **kwargs): #1.先造出Student的空对象 obj = self.__new__(self) #2.为该空对象初始化独有的属性 self.__init__(obj, *args, **kwargs) #3.返回一个初始化好的对象 return obj class Student(metaclass=My): def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex obj = Student('wangke', 25, 'male') print(obj.__dict__)
八.单例模式
单例模式是一种设计模式(套路)。一个类如果只有一个实例,那么该类称为单例。它可以节省内存空间。

class My(type): obj = None def __call__(self, *args, **kwargs): if not My.obj: obj = object.__new__(self) self.__init__(obj, *args, **kwargs) My.obj = obj return My.obj class People(metaclass=My): def __init__(self, name, age): self.name = name self.age = age @classmethod def get(cls): if not cls.obj: obj = cls('wangke', 25) cls.obj = obj return cls.obj # p = People.get() # <__main__.People object at 0x0000024845849978> # p0 = People.get() # <__main__.People object at 0x0000024845849978> # print(p) # print(p0) p1 = People('wangke', 25) p2 = People('wangke', 25) print(p1) # <__main__.People object at 0x000002154DD19A20> print(p2) # <__main__.People object at 0x000002154DD19A20>

class MyMeta(type): obj = None def __call__(self, *args, **kwargs): if not MyMeta.obj: obj = object.__new__(self) self.__init__(obj,*args,**kwargs) MyMeta.obj = obj return MyMeta.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 都返回同一个实例 即可 @classmethod def get_printer(cls): if not cls.obj: obj = cls("ES005","爱普生","彩色打印机") cls.obj = obj print("创建了新的对象") return cls.obj # 以下三个对象 的数据完全相同 但是却 占用三分内存空间 # p1 = Printer("ES005","爱普生","彩色打印机") # p2 = Printer("ES005","爱普生","彩色打印机") # p3 = Printer("ES005","爱普生","彩色打印机") # 现在要处理问题就是 如何能够限制该类 只能实例化一个对象 p = Printer.get_printer() print(p) p = Printer.get_printer() print(p) p = Printer.get_printer() print(p) p = Printer.get_printer() print(p) p1 = Printer("ES005","爱普生","彩色打印机") p2 = Printer("ES005","爱普生","彩色打印机") print(p1) print(p2) # print(p1,p2,p3) # p1.printing("一本小说....")