Python 中的魔术方法(六)属性访问控制, __getattr__ 和 __getattribute__

本文探讨了Python中`__getattr__`、`__getattribute__`、`__setattr__`和`__delattr__`特殊方法的区别及在自定义DotDict类中的使用。通过实例展示如何利用这些方法实现属性查找、设置和删除的定制行为,以及避免无限递归的问题。

1. __getattr__ 和 __getattribute__区别

__getattr__只在没有找到目标属性时调用。很适合作为属性缺失时的缺省回调函数。

__getattribute__在查看对象的实际属性之前调用,需要注意避免无限递归。

 一个代码示例来展示两个方法的使用, 创建一个自定义字典, 可以使用 obj.attr 的语法来访问字典内的数据。 如 obj = {"a": "b"} , obj.a 返回 b。  增加一个size属性,返回字典数据个数。

In [1]: from collections import UserDict
   ...:
   ...: class DotDict(UserDict):
   ...:     def __init__(self, *args, **kwargs):
   ...:         super().__init__(*args, **kwargs)
   ...:         self.size = len(self)
   ...:
   ...:     def __getattribute__(self, name: str):
   ...:         return super().__getattribute__(name.lower())
   ...:
   ...:     def __getattr__(self, name):
   ...:         return self[name]
I
`__getattr__` `__getattribute__` 都是 Python 中的魔术方法,用于在类中处理属性的访问。两者有一些区别: - `__getattr__` 方法在访问一个不存在的属性时被调用。如果实现了 `__getattr__` 方法,那么在访问一个不存在的属性时,Python 解释器会自动调用该方法并将属性名作为参数传递给它。该方法应该返回一个值来代替访问的属性。如果该方法无法提供属性的值,那么 Python 解释器会引发 `AttributeError` 异常。 - `__getattribute__` 方法在访问一个属性时被调用。该方法在访问任何属性时都会被调用,而不仅仅是不存在的属性。如果实现了 `__getattribute__` 方法,那么在访问属性时,Python 解释器会自动调用该方法并将属性名作为参数传递给它。该方法应该返回属性的值。如果该方法无法提供属性的值,那么 Python 解释器会引发 `AttributeError` 异常。 下面是一个简单的例子,演示了 `__getattr__` `__getattribute__` 方法的用法: ```python class MyClass: def __init__(self): self.data = {} def __getattr__(self, name): if name in self.data: return self.data[name] else: raise AttributeError(f"'MyClass' object has no attribute '{name}'") def __getattribute__(self, name): if name == 'data': return object.__getattribute__(self, 'data') elif name in self.data: return self.data[name] else: raise AttributeError(f"'MyClass' object has no attribute '{name}'") ``` 在上述代码中,我们定义了一个名为 `MyClass` 的类,该类包含一个字典属性 `data`。我们分别实现了 `__getattr__` `__getattribute__` 方法。在 `__getattr__` 方法中,我们检查所访问的属性是否存在于字典中。如果是,我们返回字典中的值;否则,我们引发一个 `AttributeError` 异常。在 `__getattribute__` 方法中,我们首先检查所访问的属性是否为 `data`。如果是,我们返回对象的 `data` 属性。否则,我们检查所访问的属性是否存在于字典中。如果是,我们返回字典中的值;否则,我们引发一个 `AttributeError` 异常。 下面是如何使用 `MyClass` 类: ```python my_obj = MyClass() my_obj.data['a'] = 1 my_obj.data['b'] = 2 print(my_obj.a) # 1 print(my_obj.b) # 2 print(my_obj.c) # AttributeError: 'MyClass' object has no attribute 'c' ``` 在上述示例中,我们创建了一个 `MyClass` 对象,并使用 `__getattr__` `__getattribute__` 方法来访问对象的属性。我们首先向对象的 `data` 字典中添加两个键值对。然后,我们尝试访问这些键值对,以及不存在的键值对。在访问存在的键值对时,`__getattr__` `__getattribute__` 方法都会返回正确的值。在访问不存在的键值对时,`__getattr__` 方法会引发 `AttributeError` 异常,而 `__getattribute__` 方法会引发一个相同的异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值