面向对象进阶-反射,内置方法
isinstance和issubclass
isinstance(obj,cls)判断对象所属类型,包括继承关系, 检查obj是不是cls的对象(传两个参数,一个是对象,一个是类)
# class A:pass # class B(A):pass # b = B() # print(isinstance(b,B)) #o,t # print(isinstance(b,A)) #o,t # l = list() # print(l) # type(l) # class mystr(str):pass # ms = mystr('alex') # print(ms) # print(type(ms) is str) # 不包含继承关系,只管一层 # print(isinstance('alex',str)) # 包含所有的继承关系
issubclass(sub, super)判断类与类之间的继承关系, 检查sub是不是super的子类(传两个参数,一个是子类,一个是父类)
# class A:pass # class B(A):pass # print(issubclass(B,A)) # print(issubclass(A,B))
反射
反射:可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),python中一切皆对象,都可以使用反射。
反射有四种方法:
hasattr:hasattr(object,name)判断一个对象是否有name属性或者name方法。有就返回True,没有就返回False
getattr:获取对象的属性或者方法,如果存在则打印出来。hasattr和getattr配套使用
需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址,如果需要运行这个方法,可以在后面添加一对()
setattr:给对象的属性赋值,若属性不存在,先创建后赋值
delattr:删除该对象指定的一个属性
1.类 静态属性 类方法 静态方法的反射
# 命名空间.XXX == getattr(命名空间,'XXX') # class Student: # ROLE = 'STUDENT' # @classmethod # def check_course(cls): # print('查看课程了') # # @staticmethod # def login(): # print('登录') # # 反射查看属性 # # print(Student.ROLE) # # print(getattr(Student,'ROLE')) # # # 反射调用方法 # # getattr(Student,'check_course')() # 类方法 # # getattr(Student,'login')() # 静态方法 # # num = input('>>>') # if hasattr(Student,num): # getattr(Student,num)()
2.对象 对象属性 方法 的反射
# class A(): # def __init__(self,name): # self.name = name # # def func(self): # print('in func') # # a = A('alex') # print(a.name) # print(getattr(a,'name')) # getattr(a,'func')()
3. 模块的反射
# import os # 别人写好的python代码的结合 # # os.rename('__init__.py','init') # # getattr(os,'rename')('init','__init__.py') # == os.rename # rename = os.rename # rename2 = getattr(os,'rename') # rename2('__init__.py','init') # os.rename('__init__.py','init') # rename('init','init2') # os.rename('init','init2')
4.反射自己模块中的内容
# def wahaha(): # print('wahaha') # # def qqxing(): # print('qqxing') # # wahaha() # qqxing() # 反射自己模块中的内容 找到自己当前文件所在的命名空间 # import sys # print(sys.modules) # import 都相当于导入了一个模块 # 模块哪个导入了 哪个没导入 在我的python解释器里应该记录下来 # import sys 是一个模块,这个模块里的所有的方法都是和python解释器相关的 # sys.modules 这个方法 表示所有在当前这个python程序中导入的模块 # '__main__': <module '__main__' from 'D:/sylar/python_workspace/day20/4.反射.py'> # print(sys.modules['__main__']) # my_file = sys.modules['__main__'] # my_file.wahaha() # my_file.qqxing() # # 'qqxing' # # 'wahaha' # getattr(my_file,'wahaha')() # getattr(my_file,'qqxing')()
内置方法
__call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
# class A: # def __call__(self, *args, **kwargs): # print('执行call方法了') # def call(self): # print('执行call方法了') # class B: # def __init__(self,cls): # print('在实例化A之前做一些事情') # self.a = cls() # self.a() # print('在实例化A之后做一些事情') # a = A() # a() # 对象() == 相当于调用__call__方法 # a.call() # A()() # 类名()() ,相当于先实例化得到一个对象,再对对象(),==>和上面的结果一样,相当于调用__call__方法 # B(A)
__len__
# len(dict) # len(tuple) str list set # class mylist: # def __init__(self): # self.lst = [1,2,3,4,5,6] # self.name = 'alex' # self.age = 83 # def __len__(self): # print('执行__len__了') # return len(self.__dict__) # # l = mylist() # print(len(l)) # len(obj)相当于调用了这个obj的__len__方法 # __len__方法return的值就是len函数的返回值 # 如果一个obj对象没有__len__方法,那么len函数会报错
__new__ (构造方法和单例模式)
# __new__ # ==> 构造方法 # __init__ # ==> 初始化方法 # class Single: # def __new__(cls, *args, **kwargs): # # print('在new方法里') # obj = object.__new__(cls) # print('在new方法里',obj) # return obj # def __init__(self): # print('在init方法里',self) # 1.开辟一个空间,属于对象的 # 2.把对象的空间传给self,执行init # 3.将这个对象的空间返回给调用者 # obj = Single() # single的new,single没有,只能调用object的new方法 # new方法在什么时候执行??? # 在实例化之后,__init__之前先执行new来创建一块空间 # 单例 # 如果一个类 从头到尾只能有一个实例,说明从头到尾之开辟了一块儿属于对象的空间,那么这个类就是一个单例类 # 单例类 class Single: __ISINCTANCE = None def __new__(cls, *args, **kwargs): if not cls.__ISINCTANCE: cls.__ISINCTANCE = object.__new__(cls) return cls.__ISINCTANCE def __init__(self,name,age): # self.name = name # self.age = age print(self) s1 = Single('alex',83) s2 = Single('taibai',40) # print(s1.name) # print(s2.name) # print(s1,s2)
__str__
# __str__ # l = [1,2,3] # 实例化一个list的对象 # # l是个对象 # print(l) # class Student: # def __str__(self): # return '%s %s %s'%(self.school,self.cls,self.name) # # def __init__(self,name,stu_cls): # self.school = 'oldboy' # self.name = name # self.cls = stu_cls # # he = Student('hezewei','py14') # # print(he) # huang = Student('huangdongyang','py14') # # print(huang) # # print(str(he)) # 内置的数据类型,内置的类,相当于执行__str__ # print('学生1 : %s'%he) # print一个对象相当于调用一个对象的__str__方法 # str(obj),相当于执行obj.__str__方法 # '%s'%obj,相当于执行obj.__str__方法
__repr__
是__str__的备胎.如果有__str__方法,那么# print %s str都先去执行__str__方法,并且使用__str__的返回值
如果没有__str__,那么 print %s str都会执行repr
repr(obj),%r
# 在子类中使用__str__,先找子类的__str__,没有的话要向上找,只要父类不是object,就执行父类的__str__ # 但是如果出了object之外的父类都没有__str__方法,就执行子类的__repr__方法,如果子类也没有, # 还要向上继续找父类中的__repr__方法. # 一直找不到 再执行object类中的__str__方法 # a = '123' # print(a) # print(repr(a)) # class A: # def __init__(self,name): # self.name = name # def __str__(self): # return '**%s**'%self.name # def __repr__(self): # return self.name # # class B(A): # def __init__(self,name): # self.name = name # def __repr__(self): # return '***' # # a = B('alex') # print(a) # print(str(a),repr(a)) # print('%s | %r'%(a,a)) # print('---%r---'%('abc')) # print('---%s---'%('abc')) # __str__ __repr__ : repr
__del__
析构方法,释放一个空间之前执行
# 构造方法 申请一个空间 # 析构方法 释放一个空间之前执行 # 某对象借用了操作系统的资源,还要通过析构方法归还回去 : 文件资源 网络资源 # 垃圾回收机制 # class A: # def __del__(self): # # 析构方法 del A的对象 会自动触发这个方法 # print('执行我了') # a = A() # del a # 对象的删除 del # print(a) # class File(): # # 处理文件的 # def __init__(self,file_path): # self.f = open(file_path) # self.name = 'alex' # # def read(self): # self.f.read(1024) # # def __del__(self): # 是去归还/释放一些在创建对象的时候借用的一些资源 # # del 对象的时候 程序员触发 # # python解释器的垃圾回收机制 回收这个对象所占得内存的时候 python自动触发的 # self.f.close() # f = File('文件名') # f.read() # 不管是主动还是被动,这个f对象总会被清理掉,被清理掉就触发__del__方法,触发这个方法就会归还操作系统的文件资源 # python解释器在内部就能搞定的事儿 # 申请一块儿空间 操作系统分配给你的 # 在这一块儿空间之内的所有事儿 归你的python解释器来管理 # a = 1 # del a # 对象 --> 内存 # f = open('wenjian') # python --> 操作系统 --> 硬盘里的文件 --> 文件操作符 # f.close() # # 文件操作符 # del f
item系列
__getitem__\__setitem__\__delitem__
# item系列 和对象使用[]访问值有联系 # obj = {'k':'v'} # print(obj) # 字典的对象 # print(obj['k']) # 在内置的模块中, # 有一些特殊的方法,要求对象必须实现__getitem__/__setitem__才能使用 # class B: # def __getitem__(self, item): # return getattr(self,item) # def __setitem__(self, key, value): # setattr(self,key,value*2) # def __delitem__(self, key): # delattr(self,key) # b = B() # # b.k2 = 'v2' # # print(b.k2) # b['k1'] = 'v1' # __setitem__ # print(b['k1']) # __getitem__ # del b['k1'] # __delitem__ # print(b['k1']) # class B: # def __init__(self,lst): # self.lst = lst # def __getitem__(self, item): # return self.lst[item] # def __setitem__(self, key, value): # self.lst[key] = value # def __delitem__(self, key): # self.lst.pop(key) # b = B(['111','222','ccc','ddd']) # print(b.lst[0]) # print(b[0]) # b[3] = 'alex' # print(b.lst) # del b[2] # print(b.lst) # 类 # 每一个对象都是一副扑克牌 # 我想查看这个对象 来查看整副牌 # 我想从这一副牌中随机抽一张牌 # 我想完成打乱这副牌的顺序的功能
__hash__
# hash方法 # 底层数据结构基于hash值寻址的优化操作 # hash是一个算法 # 能够把某一个要存在内存里的值通过一系列计算, # 保证不同值的hash结果是不一样的 # '127647862861596' ==> 927189778748 # 对同一个值在多次执行python代码的时候hash值是不同 # 但是对同一个值 在同一次执行python代码的时候hash值永远不变 # print(hash('abc')) # 6048279107854451739 # print(hash('abc')) # print(hash('abc')) # print(hash('abc')) # print(hash('abc')) # print(hash('abc')) # 字典的寻址 - hash算法 # d = {'key':'value'} # hash - 内置函数 # set集合 # se = {1,2,2,3,4,5,'a','b','d','f'} # print(se) # d = {'key':'v1','key':'v2'} # print(d['key']) # hash(obj) #obj内部必须实现了__hash__方法
__eq__
class A: def __init__(self,name,age): self.name = name self.age = age def __eq__(self, other): if self.name == other.name and self.age == other.age: return True a = A('alex',83) aa = A('alex',83) aa2 = A('alex',83) aa3 = A('alex',83) aa4 = A('alex',83) aa5 = A('alex',83) aa6 = A('alex',83) print(a,aa) print(aa3 == aa == aa4) # ==这个语法 是完全和__eq__
幻想毫无价值,计划渺如尘埃,目标不可能达到。这一切的一切毫无意义——除非我们付诸行动。