__getattr__
和 __getattribute__
都是 Python 中用于属性访问的特殊方法(魔术方法),但它们的使用场景和行为有所不同。以下是它们之间的主要区别:
###1. 调用时机- __getattribute__(self, name)
:
-
当访问任何属性时都会被调用,不论该属性是否存在于对象的属性字典中。
-
它是所有属性访问的基础,包括现有属性和不存在的属性。
-
__getattr__(self, name)
:
-仅在尝试访问不存在的属性时才会被调用。 -
如果访问的属性在对象的属性字典中存在,则不会触发
__getattr__
。
###2. 使用场景- __getattribute__
:
-
可以用于全局拦截对所有属性的访问,不管属性是否存在。
-适合场景包括记录访问日志、实现代理等。 -
__getattr__
:
-适合用于提供默认行为或动态计算属性值,尤其在属性不存在时。 -
常用于处理未定义的属性请求,比如实现懒加载、代理等。
###3. 示例以下是简单的示例来说明这两者的区别:
def __init__(self): self.existing_attr = "I'm here!" def __getattribute__(self, name): print(f"__getattribute__ called for {name}") return super().__getattribute__(name)
# 调用父类的方法
def __getattr__(self, name): print(f"__getattr__ called for {name}") return f"{name} does not exist!" #处理不存在的属性obj = Example() #访问现有属性
print(obj.existing_attr) #触发 __getattribute__ #访问不存在的属性
print(obj.non_existing_attr)
#触发 __getattribute__,然后是 __getattr__
输出:
rust
__getattribute__ called for existing_attrI'm here! __getattribute__ called for non_existing_attr__getattr__ called for non_existing_attrnon_existing_attr does not exist!
总结- __getattribute__
是一个全面的拦截器,处理所有的属性访问,包括已存在和未存在的属性。
__getattr__
是一个后备支持,当请求一个未定义的属性时调用。
理解这两者的差异可以帮助你更好地控制对象属性的访问和处理。