python魔术方法二
反射
- 概述
运行时,runtime
区别于编译时,指的是程序被加载到内存中执行的时候。反射reflection
,指的是运行时获取类型定义信息。
一个对象能够在运行时,像照镜子一样,反射出其类型信息。
简单说,在Python中,能够通过一个对象,找出其type
,class
,attribute
或method
的能力,称为反射或者自省。
具有反射能力的函数有type()
,isinstance()
,callable()
,dict()
,getattr()
内建函数 |
意义 |
getattr(object,name[,default]) |
通过name 返回object 的属性值。当属不存在,将使用default 返回,如果没有default , 则抛出AttributeError ,name 必须为字符串 |
setattr(object,name,value) |
object 的属性存在,则覆盖,不存在,新增 |
hasattr(object,name) |
判断对象是否有这个名字的属性, name 必须为字符串 |
# __getattr__ __setattr__ __delattr__ __getattribute__
| class Point: |
| def __init__(self,x,y) -> None: |
| self.x = x |
| self.y = y |
| |
| def showme(self): |
| return '<{}:{}>'.format(self.x,self.y) |
| |
| |
| t = Point(1,2) |
| print(t.x,t.y) |
| print(t.showme,t.showme()) |
| print(getattr(t,'x')) |
| print(getattr(t,'y')) |
| print(t.y) |
| |
| |
| |
| |
| setattr(Point,'showme', |
| lambda self: '< --- {}:{} --->'.format(self.x,self.y) |
| ) |
| print(t.showme()) |
| |
| |
| |
| print(hasattr(t,'x')) |
| print(hasattr(t,'z')) |
| class Point: |
| |
| def __init__(self,x,y) -> None: |
| self.x = x |
| self.y = y |
| |
| def showme(self): |
| return '<{}:{}>'.format(self.x,self.y) |
| |
| def __getattr__(self,name): |
| return 'no such attr {}'.format(name) |
| |
| t = Point(2,2) |
| print(t.x) |
| print(t.y) |
| print(t.z) |
# __setattr__ 当设置一个属性的时候,会调用这个方法: self.x = x或setattr(t,'x',x)调用,解决方法1.调用object同名的方法 super().__setattr__(key,value) 2.使用自己的实例字典 self.__dict__[key] = value
| class Point: |
| |
| def __init__(self,x,y) -> None: |
| self.x = x |
| self.y = y |
| |
| def __setattr__(self,key , value): |
| print('setattr ---') |
| |
| self.__dict__[key] = value |
| |
| t = Point(1,2) |
| print(t.x) |
# __delattr__ del 实例.xxx 都会触发魔术方法__delattr__的调用
| class Point: |
| |
| def __init__(self,x,y) -> None: |
| self.x = x |
| self.y = y |
| |
| def __delattr__(self,item): |
| print('del {} ---'.format(item)) |
| super().__delattr__(item) |
| |
| t = Point(1,2) |
| print(1, t.x) |
| del t.x |
| print(t.__dict__) |
| |
| |
| |
# __getattribute__ 属性访问第一站, 当访问一个属性的时候,会调用这个方法,返回值就是这个属性的值
| class Point: |
| |
| def __init__(self,x,y) -> None: |
| self.x = x |
| self.y = y |
| |
| def __getattribute__(self,item): |
| print('getattribute ---') |
| |
| ret = object.__getattribute__(self,item) |
| return ret * 10 |
| |
| t = Point(1,2) |
| print(t.x) |
# __getattribute__ 属性访问第一站, 一般建议不要定义它,如果定义了,为了正常访问属性,需要调用父类的方法,以免陷入死循环
| class Point: |
| |
| def __init__(self,x,y) -> None: |
| self.x = x |
| self.y = y |
| |
| def __getattr__(self, item): |
| return self.__dict__[item] * 10 |
| |
| def __getattribute__(self,item): |
| print('getattribute ---') |
| if item != '__dict__': |
| raise AttributeError('no such attr {}'.format(item)) |
| return super().__getattribute__(item) |
| |
| t = Point(1,2) |
| print(t.x) |
魔术方法 |
意义 |
__getattr__() |
当通过搜索实例、实例的类及祖先类查不到属性时,就会调用此方法。 |
__setattr__() |
通过. 访问实例属性,进行增加、修改都要调用它。 |
__delattr__() |
当通过实例来删除属性时调用此方法。 |
__getattribute__ |
实例所有的属性调用都从这个方法开始。 |
实例属性查找顺序
实例调用__getattribute__()
—> instance.__dict__
—> instance.__class__.__dict__
—> 继承的祖先类(直到object
)的__dict__
—> 调用__getattr__()