抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

python魔术方法二

反射

  • 概述
    运行时,runtime区别于编译时,指的是程序被加载到内存中执行的时候。反射reflection,指的是运行时获取类型定义信息。
    一个对象能够在运行时,像照镜子一样,反射出其类型信息。
    简单说,在Python中,能够通过一个对象,找出其type,class,attributemethod的能力,称为反射或者自省。
    具有反射能力的函数有type(),isinstance(),callable(),dict(),getattr()
内建函数 意义
getattr(object,name[,default]) 通过name返回object的属性值。当属不存在,将使用default返回,如果没有default, 则抛出AttributeErrorname必须为字符串
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()) # < --- 1:2 --->

# 看有没有这个属性

print(hasattr(t,'x')) # True
print(hasattr(t,'z')) # False
class Point:
    # z = 100 #假如这里有z,那么就不会调用__getattr__方法,print(t.z) # 100 
    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) # 2
print(t.y) # 2
print(t.z) # no such attr z # 先是实例的字典中有没有z,mro 中从左到右所有类开始找,找到了就返回,找不到就调用__getattr__方法
  • # __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 ---')
        # super().__setattr__(key,value) # 自己解决不了的时候,调用父类的方法
        self.__dict__[key] = value # 调用字典 

t = Point(1,2)
print(t.x) # 1
  • # __delattr__ del 实例.xxx 都会触发魔术方法__delattr__的调用
class Point:
    # z = 100 # 当 del Point.z 只要通过实例删除,都会调用__delattr__方法
    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__) # {'y': 2} # 删除了x属性

# del x ---
# {'y': 2}
  • # __getattribute__ 属性访问第一站, 当访问一个属性的时候,会调用这个方法,返回值就是这个属性的值
class Point:

    def __init__(self,x,y) -> None:
        self.x = x 
        self.y = y 

    def __getattribute__(self,item):
        print('getattribute ---')
        # return super().__getattribute__(item)
        ret =  object.__getattribute__(self,item)
        return ret * 10

t = Point(1,2)
print(t.x) # 10
  • # __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) # 10
  • 总结
魔术方法 意义
__getattr__() 当通过搜索实例、实例的类及祖先类查不到属性时,就会调用此方法。
__setattr__() 通过.访问实例属性,进行增加、修改都要调用它。
__delattr__() 当通过实例来删除属性时调用此方法。
__getattribute__ 实例所有的属性调用都从这个方法开始。

实例属性查找顺序

实例调用__getattribute__() —> instance.__dict__ —> instance.__class__.__dict__ —> 继承的祖先类(直到object)的__dict__ —> 调用__getattr__()

评论