python class __getattr__ 与 __getattribute__ 的区别

在Python中,__getattr__是一个特殊的方法,用于处理访问不存在的属性时的行为。它通常在类中被重写,以便在属性访问失败时提供自定义的处理逻辑。

__getattr__ 的使用

1. 基本用法

__getattr__方法在访问类实例的某个不存在的属性时自动调用。其签名如下:

def __getattr__(self, name):
    # 自定义处理逻辑
    pass
  • self:指向实例对象本身。
  • name:要访问的不存在的属性的名称。
2. 示例

以下是一个简单的示例,展示如何使用__getattr__

class MyClass:
    def __init__(self, existing_attribute):
        self.existing_attribute = existing_attribute
    
    def __getattr__(self, name):
        return f"The attribute '{name}' does not exist"

# 创建对象
obj = MyClass("Hello")

# 访问存在的属性
print(obj.existing_attribute)  # 输出: Hello

# 访问不存在的属性
print(obj.non_existent_attribute)  # 输出: The attribute 'non_existent_attribute' does not exist
3. 实现动态属性

可以使用__getattr__来实现动态属性:

class DynamicAttributes:
    def __init__(self, base_value):
        self.base_value = base_value
    
    def __getattr__(self, name):
        if name.startswith("dynamic_"):
            return f"Dynamic value based on {self.base_value} and {name}"
        raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

# 创建对象
obj = DynamicAttributes(10)

# 访问动态属性
print(obj.dynamic_example)  # 输出: Dynamic value based on 10 and dynamic_example

# 访问不存在的普通属性会引发 AttributeError
print(obj.some_other_attribute)  # 输出: AttributeError: 'DynamicAttributes' object has no attribute 'some_other_attribute'

__getattr____getattribute__ 的区别

  • __getattr__:仅在访问不存在的属性时调用。
  • __getattribute__:每次访问属性时都会调用,不论该属性是否存在。因此,如果使用__getattribute__,必须特别小心以避免无限递归。
__getattribute__ 示例
class MyClass:
    def __init__(self, value):
        self.value = value
    
    def __getattribute__(self, name):
        print(f"Accessing attribute: {name}")
        return super().__getattribute__(name)

# 创建对象
obj = MyClass(100)

# 访问属性
print(obj.value)  # 输出: Accessing attribute: value\n100

典型应用场景

  1. 延迟加载属性:当某些属性的计算开销较大且可能并不总是需要时,可以使用__getattr__在第一次访问时计算并缓存这些属性。

  2. 代理模式:在代理对象中,将对不存在属性的访问转发到实际对象。

class RealObject:
    def __init__(self):
        self.existing_attribute = "I'm real"

class Proxy:
    def __init__(self, real_object):
        self._real_object = real_object
    
    def __getattr__(self, name):
        return getattr(self._real_object, name)

# 创建真实对象和代理对象
real = RealObject()
proxy = Proxy(real)

# 通过代理对象访问真实对象的属性
print(proxy.existing_attribute)  # 输出: I'm real
  1. 配置管理:在动态生成配置项时,可以通过__getattr__来实现。
class Config:
    def __init__(self, settings):
        self._settings = settings
    
    def __getattr__(self, name):
        return self._settings.get(name, None)

# 创建配置对象
settings = {'host': 'localhost', 'port': 8080}
config = Config(settings)

# 访问配置项
print(config.host)  # 输出: localhost
print(config.port)  # 输出: 8080
print(config.debug)  # 输出: None

通过__getattr__,可以使类的属性访问更加灵活,满足特定需求。合理使用这个方法可以增强代码的动态性和适应性,但滥用可能导致代码难以调试和维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少陽君

谢谢老板的拿铁

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值