__getattr__、__setattr__、__delattr__、__getattribute__ 魔法方法的调用

class Test(object):
    def __getattr__(self, item):
        print('没有找到属性时,触发AttributeError异常时会调用此方法')
        return f"没有找到 {item} 属性时 ,会调用此方法"

    def __setattr__(self, key, value):
        object.__setattr__(self, key, value)    # Implement setattr(self, name, value)
        print('设置属性,会调用此方法')

    def __delattr__(self, item):
        object.__delattr__(self, item)  # Implement delattr(self, name)
        print('属性被删除了')

    def __getattribute__(self, item):
        print('查找属性时,首先会进入该方法中')
        object.__getattribute__(self, item) # return getattr(self, name)
        print("上行代码已经进行了return,所以这行代码不会打印出来的,下一步会进入到__getattr__(self, item)中执行。")

obj = Test()
print(obj.foh)
obj.age = 19
del obj.age

代码执行结果:
image

这段代码涉及到 Python 的魔术方法(特殊方法),这些方法允许你定制类的属性访问、设置和删除行为。
特别是在 __getattr__、__setattr__、__delattr__ 和 __getattribute__ 等方法中,
object.__setattr__、object.__delattr__ 和 object.__getattribute__ 被直接调用。
它们是对父类 object 类中相应方法的显式调用。让我们来详细分析它们的作用和原因。
1. object.__setattr__(self, key, value) 的作用
在 __setattr__ 方法中,object.__setattr__(self, key, value) 是用来
调用父类的 __setattr__ 方法来真正设置属性的。

1.__setattr__ 是当你给对象的属性赋值时调用的方法。如果你重写了这个方法,
就需要确保你手动调用父类的 __setattr__ 来实际设置属性,否则就会进入无限递归(因为每次调用 __setattr__ 时都会再次调用自己)。
2.object.__setattr__(self, key, value) 直接调用的是 Python object 类的原始 __setattr__ 方法,该方法会直接修改对象的属性。

为什么加这行?
如果你不调用 object.__setattr__(self, key, value),你就没有办法在 __setattr__ 中真正为对象设置属性。
通过调用父类的方法,我们能确保在重载 __setattr__ 时保留默认的属性设置功能。
2. object.__delattr__(self, item) 的作用
在 __delattr__ 方法中,object.__delattr__(self, item) 是用来调用父类的 __delattr__ 方法来删除对象的属性。

3.__delattr__ 是当你删除对象的属性时调用的方法。如果你重写了这个方法,你同样需要显式调用父类的 __delattr__,否则属性就不会被删除。
4.object.__delattr__(self, item) 直接调用父类 object 类中的 __delattr__ 方法,它会处理属性的删除操作。

为什么加这行?
没有调用 object.__delattr__(self, item),你就不能在删除属性时执行正常的删除操作。
因此,必须调用父类的 __delattr__ 方法来确保删除行为的正常执行,避免属性删除操作失败。
3. object.__getattribute__(self, item) 的作用
在 __getattribute__ 方法中,object.__getattribute__(self, item) 是用来调用父类的 __getattribute__ 方法来获取对象的属性。

5.__getattribute__ 是每次访问对象的属性时都会调用的方法。如果你重写了 __getattribute__,它会被所有属性访问触发。
6.object.__getattribute__(self, item) 会直接调用 object 类中的 __getattribute__ 方法,真正访问属性值。

为什么加这行?
如果你不调用 object.__getattribute__(self, item),你就无法获取对象的属性值。通过显式调用父类的 __getattribute__,
我们确保在 __getattribute__ 中的自定义行为不会影响原有属性访问的机制。
这三行代码的综合作用

7.object.__setattr__:确保 __setattr__ 中的自定义行为不会阻止属性的正常赋值。当你重载了 __setattr__ 时,
你必须手动调用父类的 __setattr__ 来保证属性能够被实际设置。
8.object.__delattr__:确保在 __delattr__ 中自定义的删除行为能正常删除对象的属性。
调用父类的 __delattr__ 是删除属性所必须的。
9.object.__getattribute__:确保 __getattribute__ 中的自定义逻辑不会阻止正常的属性访问。
调用父类的 __getattribute__ 是必须的,以保证属性访问的正常执行。

代码示例的执行流程
假设你有如下代码:
test = Test()
test.name = "Hello"  # 这将调用 __setattr__,设置 name 属性
print(test.name)  # 这将调用 __getattribute__ 来获取 name 属性
del test.name  # 这将调用 __delattr__,删除 name 属性


10.设置属性:调用 test.name = "Hello" 会触发 __setattr__ 方法,
其中调用 object.__setattr__(self, key, value) 实际设置 name 属性值。

11.获取属性:调用 print(test.name) 会触发 __getattribute__ 方法,
其中调用 object.__getattribute__(self, item) 实际访问 name 属性值。

12.删除属性:调用 del test.name 会触发 __delattr__ 方法,
其中调用 object.__delattr__(self, item) 实际删除 name 属性。

总结

13.object.__setattr__:在 __setattr__ 中调用父类方法来确保属性被设置。
14.object.__delattr__:在 __delattr__ 中调用父类方法来确保属性被删除。
15.object.__getattribute__:在 __getattribute__ 中调用父类方法来确保属性被正确访问。

这些显式调用父类方法的操作确保你在重载这些方法时,不会丢失对象属性的基本功能,从而使你能够在这些方法中加入自定义逻辑。

posted @ 2025-09-04 21:36  大海一个人听  阅读(14)  评论(0)    收藏  举报