如何创建支持属性式与字典式访问的Python对象?
实现同时支持属性访问与字典键访问的Python对象
要实现类似xarray Dataset的双访问模式,核心是让对象同时支持属性式访问(.var)和字典键式访问(['var']),下面提供两种实用的实现方案:
方案一:继承dict并重写属性访问方法
利用dict本身的字典访问能力,仅需补充属性访问的逻辑:
class DualAccessDict(dict): def __getattr__(self, name): # 当属性访问失败时,尝试从字典键中获取 try: return self[name] except KeyError: raise AttributeError(f"'DualAccessDict' object has no attribute '{name}'") from None def __setattr__(self, name, value): # 优先处理字典键,避免覆盖类的内置方法(如keys()、items()) if name in self or name not in dir(self): self[name] = value else: # 若为类本身的属性,调用父类方法设置 super().__setattr__(name, value) def __delattr__(self, name): # 优先删除字典键,失败则删除实例属性 try: del self[name] except KeyError: super().__delattr__(name)
使用示例
dd = DualAccessDict() dd['var1'] = 100 print(dd.var1) # 输出: 100 dd.var2 = 200 print(dd['var2']) # 输出: 200 del dd.var1 print('var1' in dd) # 输出: False
方案二:自定义类维护内部字典(更灵活)
如果不想继承dict,可自行维护内部数据字典,实现完整的映射协议:
class DualAccessObject: def __init__(self, **kwargs): self._data = kwargs # 实现字典键访问 def __getitem__(self, key): return self._data[key] def __setitem__(self, key, value): self._data[key] = value def __delitem__(self, key): del self._data[key] # 实现属性访问 def __getattr__(self, name): try: return self._data[name] except KeyError: raise AttributeError(f"'DualAccessObject' object has no attribute '{name}'") from None def __setattr__(self, name, value): # 区分内部属性与数据键,避免递归问题 if name == '_data': super().__setattr__(name, value) else: self._data[name] = value def __delattr__(self, name): if name == '_data': super().__delattr__(name) else: try: del self._data[name] except KeyError: raise AttributeError(f"'DualAccessObject' object has no attribute '{name}'") from None # 可选:添加字典常用方法,提升兼容性 def keys(self): return self._data.keys() def items(self): return self._data.items() def values(self): return self._data.values() # 可选:让IDE自动补全能识别数据键 def __dir__(self): return super().__dir__() + list(self._data.keys())
使用示例
obj = DualAccessObject(var1=10) print(obj.var1) # 输出: 10 print(obj['var1']) # 输出: 10 obj.var2 = 20 print(obj['var2']) # 输出: 20 del obj.var1 print('var1' in obj._data) # 输出: False
注意事项
- 避免数据键与类内置方法重名(如
keys、items),否则属性访问会优先调用类方法而非数据键。若需支持此类场景,可重写__getattribute__方法(需注意递归陷阱)。 - 若要完全模拟xarray的行为,可额外实现
__repr__、__len__等方法,优化对象的打印与交互体验。
内容的提问来源于stack exchange,提问作者Marti
相关产品推荐
相关产品推荐

