Python笔记:魔术方法----与属性相关的魔术方法(__getattribute__,__getattr__,__setattr__,delattr__)

属性查找顺序
正常情况下,属性查找都是以一定的规则从__dict__中查找的。 如果只有类属性x,没有实例属性x,当访问x的时候,会是如何呢?我们来看下面例子:

class Test(object):
    x = 8
    def __init__(self,c):
        pass
t= Test(6)
t.x

print(t.x)

# 输出结果:

>>>>>8

以上例子中,表明当没有实例属性时即查找不到实例属性,会查找类属性。
属性访问的默认行为是从一个对象的字典中获取、设置或删除属性。例如,a.x 的查找顺序会从 a.__dict__['x']开始,然后是 type(a).__dict__['x'],接下来依次查找 type(a) 的上级基类,不包括元类。
注意:当类中定义了__slots__属性时,对象就不会有__dict__属性了,这时访问属性时,是通过类似描述符的方式查找属性的。
一般情况下,python的属性访问机制是:实例属性,类属性,父类属性,object属性;也就是先查找实例对象的__dict__属性,没有的话再查找类__dict__属性,再没有的话查找父类的__dict__属性,最后是基类object属性。当定义了数据描述符时时,会覆盖实例对象的__dict__属性;非数据描述符访问属性时,先查找对象的__dict__属性,没有的话再调用描述符的__get__方法。
属性访问顺序:

  • 调用__getattribute__
  • 调用数据描述符(同时定义__get__(),__set__()的描述符)
  • 调用实例对象属性
  • 调用类的属性
  • 调用非数据描述符(仅定义__get__()的描述符)
  • 调用父类的属性
  • 调用__getattr__(属性不存在时调用)
    在这里插入图片描述
    __getattribute__

触发时机:访问对象的成员属性的时候自动触发,无论该成员属性是否存在
作用:可以在用户访问成员属性的时候进行数据处理等操作
参数:self接收当前对象,第二个参数接收访问的成员属性名称字符串 (object.__getattribute__(self, name))
返回值:可有可无,没有的话就返回None
注意事项:在该魔术方法中,禁止使用 当前对象.成员(self.XX)的方式(例如:self.name)访问成员,否则会发生递归次数过大的错误RecursionError: maximum recursion depth exceeded while calling a Python object

class Human:
    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18
    def __getattribute__(self, item):
        print('getattribute call by %s' % self)
        # return self.name   如果返回的是self.name,则会报错
        return super().__getattribute__(item)
    def eat(self):
        print('eat method is running')
        
human = Human()
print(human.name)
print(human.age)

# 输出结果:

>>>>>getattribute call by <__main__.Human object at 0x03EAD088>
>>>>>Python
>>>>>getattribute call by <__main__.Human object at 0x03EAD088>
>>>>>18

__getattr__

触发时机:访问不存在的对象成员属性的时候自动触发
作用:防止访问不存在的对象成员的时候报错;为不存在的成员定义值
参数:self接收当前对象,第二个参数接收访问的成员属性名称字符串(object.__getattr__(self, name))
返回值:可有可无,没有的话就返回None
注意事项:__getattribute__和__getattr__可以同时存在,如果同时存在,那么在访问不存在的值时,__getattribute__和__getattr__都会触发

该方法定义了你试图访问一个不存在的属性时的行为。因此,重载该方法可以实现捕获错误拼写然后进行重定向, 或者对一些废弃的属性进行警告。

class Human:
    # 成员属性
    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18
    def __getattr__(self, item):
        if item == 'score':
            return 80
        else:
            return 'No Attribution'
    def eat(self):
        print('eat method is running')
        
human = Human()
print(human.score)
print(human.school)

# 输出结果:
>>>>>80
>>>>>No Attribution

__setattr__

触发时机:添加或者修改对象成员的时候自动触发
作用:可以限制或者管理对象成员的添加或修改操作
参数:self接收当前对象,第二个参数接收设置的成员名称字符串,第三个参数接收设置的值(object.__setattr__(self, name, value))
返回值:无
注意事项:在该魔术方法中,禁止使用当前对象.成员=值 的方式(例如:self.name = ‘Mike’)设置成员,否则会发生递归次数过大的错误RecursionError: maximum recursion depth exceeded while calling a Python object

class Human:
    # 成员属性
    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18
    def __setattr__(self, item,value):
        if item == "score": # 限制添加score
            pass
        else:
            return super(Human,self).__setattr__(item,value) # 此处不可以用self.key = value,也可用self.__dict__[key]=value 前提没有__slots__
    def eat(self):
        print('eat method is running')

human = Human()
human.score = 80
#print(human.score) # 报错AttributeError: 'Human' object has no attribute 'score'
human.id = 11010
print(human.id)

# 输出结果:
>>>>>11010

__delattr__

触发时机:删除对象成员的时候自动触发
作用:可以限制删除对象成员或者在删除时执行额外的工作
参数:self接收当前对象,第二个参数接收删除的成员名称字符串 (object.__delattr__(self, name))
返回值:可有可无,无的话则不会执行删除操作
注意事项:在该魔术方法中,禁止使用 del 当前对象.成员 的方式(例如:del self.name)删除成员,否则会发生递归次数过大的错误RecursionError: maximum recursion depth exceeded while calling a Python object

class Human:
    def __init__(self):
        self.name = 'Python'
        self.sex = 'male'
        self.age = 18
    def __delattr__(self, item):
        if item == 'name': # 当删除的对象成员名称为name时,不执行删除操作,即限制了删除name成员
            pass
        else:
            # del self.sex  如果执行此行,则会报错,递归数过大
            return super().__delattr__(item)
    def eat(self):
        print('eat method is running')

human = Human()
del human.name  # 不会删除name属性
del human.sex  # 会删除sex属性
print(human.name)
print(human.sex)

# 输出结果:
Python
报错AttributeError: 'Human' object has no attribute 'sex'

参考来源:https://www.jianshu.com/p/892792cb774d
https://www.cnblogs.com/wangchengpei/p/11116546.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值