Python Day 23 面向对象进阶(内置方法:反射,isinstance和issubclass,__str__和__repr__和其他双下方法)
反射
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
使用字符串数据类型的变量名来操作一个变量的值,使用反射获取某个命名空间中的值.需要有一个变量指向这个命名空间的字符串数据类型的名字,再使用getattr获取值,如果是变量能直接获得结果,如果是函数,只能拿到内存地址,加上括号就是执行
反射的几种用法
使用类名反射 : 静态属性、类方法、静态方法 使用对象名反射 :对象属性、类中的普通方法 使用模块名反射 : 变量 函数 类 在自己所在的文件中反射全局变量 :getattr(sys.modules[__name__],'要反射的名字')
hasattr
判断是否存在,返回True,False (检测是否含有某属性)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: Name1 = 'alex' Name2 = 'egon' Name3 = 'guangtou' def __init__(self,name): self.name = name def func(self): print('in func',self.name ) if hasattr(A,'Name1'): #类名 静态属性名(字符串类型) print(getattr(A,'Name1')) #类名 静态属性名(字符串类型)
getattr
获取属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: Name1 = 'alex' Name2 = 'egon' Name3 = 'guangtou' def __init__(self,name): self.name = name def func(self): print('in func',self.name ) if hasattr(A,'Name1'): #类名 静态属性名(字符串类型) print(getattr(A,'Name1')) #类名 静态属性名(字符串类型)
setattr
添加和修改属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: Name1 = 'alex' Name2 = 'egon' Name3 = 'guangtou' def __init__(self,name): self.name = name def func(self): print('in func',self.name ) if hasattr(A,'Name1'): print(getattr(A,'Name1')) print(A.__dict__) A.Country = '中国' #增加 print(A.__dict__) A.Country = '印度' #修改 print(A.__dict__) setattr(A,'Country','日本') print(A.__dict__) setattr(A,'Country','德国') print(A.__dict__)
delattr
删除属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class A: Name1 = 'alex' Name2 = 'egon' Name3 = 'guangtou' def __init__(self,name): self.name = name def func(self): print('in func',self.name ) if hasattr(A,'Name1'): print(getattr(A,'Name1')) print(A.__dict__) delattr(A,'Name1') print(A.__dict__)
isinstance和issubclass
isinstance
判断对象和类的关系
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
a = 10 print(isinstance(a,int)) #判断对象类型 class F:pass class Foo(F):pass obj = Foo() print(isinstance(obj,Foo)) #对象属于Foo类 True print(isinstance(obj,F)) #可以判断继承关系 True print(type(obj) is Foo) #对象属于Foo类 True print(type(obj) is F) #无法判断继承类 False
issubclass
判断是子类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class F:pass class Foo(F):pass print(issubclass(Foo,F)) print(issubclass(F,Foo))
__str__和__repr__
改变对象的字符串显示 必须返回一个str数据类型
__str__ %s str() print()
__repr__ %r repr()
当__str__存在时 %s 使用__str__方法,__repr__存在时 %s 使用__repr__方法,
当__str__不存在时 %s 使用__repr__方法,__repr__存在时 %s 使用__repr__方法,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class B: def __str__(self): return 'str : class B' def __repr__(self): return 'repr : class B' b = B() print('%s' % b) print('%r' % b) ================== str : class B # repr : class B # ******************************* ******************************* class B: # def __str__(self): # return 'str : class B' def __repr__(self): return 'repr : class B' b = B() print('%s' % b) print('%r' % b) ================== repr : class B repr : class B
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
str函数或者print函数--->obj.__str__() repr或者交互式解释器--->obj.__repr__() 如果__str__没有被定义,那么就会使用__repr__来代替输出 注意:这俩方法的返回值必须是字符串,否则抛出异常
__format__ format()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
format_dict={ 'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型 'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址 'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,addr,type): self.name=name self.addr=addr self.type=type def __format__(self, format_spec): # format_spec = 'nat' if not format_spec or format_spec not in format_dict: format_spec='nat' fmt=format_dict[format_spec] # fmt = '{obj.name}-{obj.addr}-{obj.type}' return fmt.format(obj=self) s1=School('oldboy1','北京','私立') print(format(s1,'nat')) print(format(s1,'tna')) print(format(s1,'tan')) print(format(s1,'asfdasdffd'))
其他双下方法
__call__
对象加上(),可以触发这个类的__call__方法。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo: def __call__(self): print('call') Foo()() #触发类的__call__方法 obj = Foo() obj() # 相当于调用__call__ ===================== call call
__len__
内置函数的len函数是依赖类中的__len__
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Classes: def __init__(self,student_lst): self.student_lst = student_lst def __len__(self):return len(self.student_lst) clas = Classes(['张三','程咬金','程咬银','程咬铁','程咬钢']) #创建一个对象 print(len(clas.student_lst)) print(len(clas))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Wahaha: def __init__(self,num,name,age): self.num = num self.name = name self.age = age def __len__(self): return len(self.__dict__) # 某个类中有多少个属性??? obj = Wahaha(6,'haha',7) print(len(obj.__dict__)) print(len(obj))
__hash__ 和 __eq__
set 依赖 __hash__和__eq__方法来完成去重
__hash__
hash值计算
__eq__
比较是否值相同
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __eq__(self, other): if type(self) == type(other) and #设置条件 self.name == other.name and self.sex == other.sex : return True else: return False p1 = Person('egon',40,'male') p2 = Person('egon',50,'male') p3 = Person('光头',80,'male') print(p1==p2) #直接比较对象 print(p1==p3)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 两个对象 的name 和 sex相同,那么这两个对象就是相同的对象 # 对100个对象进行去重 class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): return hash(self.name+self.sex) def __eq__(self, other): if type(self) == type(other) and self.name == other.name and self.sex == other.sex : return True else: return False person_lst = [Person('egon',i,'male') for i in range(100)] print(set(person_lst)) # hash是否相等,值是否相等 __hash__值相等,__eq__值也相等 print(hash(person_lst[1])) print(hash(person_lst[2])) # 根据每一个对象的hash值