You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在嵌套调用中优先调用setattr而非getattr?实现可编辑嵌套结构

实现支持嵌套赋值自动创建、访问不存在属性抛错的嵌套结构

核心需求实现思路

要实现「赋值时自动创建中间属性,访问不存在属性时抛出AttributeError」,关键在于区分赋值场景和单纯访问场景:

  • 赋值场景(如e.a.b.c = 1):需要自动创建路径中不存在的中间实例
  • 单纯访问场景(如print(e.a.b.d)):必须抛出异常,不能自动创建

现有代码的问题在于:

  1. __getattr__与get方法绑定,访问不存在属性时会自动创建实例,导致行为类似defaultdict,不符合访问抛错的需求
  2. set方法中引用了未定义的self.delimiter属性,会触发报错
  3. get方法内部嵌套定义同名函数,存在逻辑混乱,且@wraps(self.get)的用法错误

解决方案代码

通过引入代理类(_Proxy)来处理赋值路径中的属性访问,只有当实际执行赋值操作时才会创建对应实例,单纯访问时则抛出异常:

from typing import Any, Optional

class _Proxy:
    def __init__(self, parent, attr_name):
        self._parent = parent
        self._attr_name = attr_name

    def _resolve(self):
        # 递归解析出实际的Example实例,不存在则创建
        if isinstance(self._parent, _Proxy):
            parent_instance = self._parent._resolve()
        else:
            parent_instance = self._parent
        
        if not hasattr(parent_instance, self._attr_name):
            setattr(parent_instance, self._attr_name, Example())
        return getattr(parent_instance, self._attr_name)

    def __getattr__(self, name):
        # 访问代理属性时,返回新的代理对象
        return _Proxy(self, name)

    def __setattr__(self, name, value):
        if name.startswith('_'):
            super().__setattr__(name, value)
            return
        # 执行赋值时,先解析出实际实例,再完成赋值
        target = self._resolve()
        setattr(target, name, value)

    def __repr__(self):
        # 单纯访问代理对象时,抛出属性不存在异常
        raise AttributeError(f"'Example' object has no attribute '{self._attr_name}'")

    __str__ = __repr__

class Example:
    def __getattr__(self, name: str) -> Any:
        # 属性不存在时返回代理对象,而非直接创建实例
        return _Proxy(self, name)

    def __setattr__(self, name: str, value: Any) -> None:
        # 直接设置当前实例的属性
        super().__setattr__(name, value)

    def __getitem__(self, name: str) -> Any:
        # 支持索引式访问,与属性访问逻辑一致
        return getattr(self, name)

    def __setitem__(self, name: str, value: Any) -> None:
        setattr(self, name, value)

    def get(self, name: str, default: Optional[Any] = None) -> Any:
        # 支持点路径的get方法,不存在则返回默认值
        parts = name.split('.')
        current = self
        for part in parts:
            try:
                current = getattr(current, part)
            except AttributeError:
                return default
        return current

测试验证

e = Example()

# 嵌套赋值:自动创建中间实例
e.a.b.c = 1
print(e.a.b.c)  # 输出: 1
print(e.a.b)    # 输出: <__main__.Example object at 0x...>

# 访问不存在属性:抛出AttributeError
try:
    print(e.a.b.d)
except AttributeError as err:
    print(err)  # 输出: 'Example' object has no attribute 'd'

try:
    print(e.x)
except AttributeError as err:
    print(err)  # 输出: 'Example' object has no attribute 'x'

# get方法支持默认值
print(e.get("a.b.c"))       # 输出: 1
print(e.get("a.b.d", 0))    # 输出: 0

内容的提问来源于stack exchange,提问作者Zhiyuan Chen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 22:50:35