在 __init__() 之后重写类方法(例如 __setattr__)



所以我最近在尝试实现某种DotDict时,想出了一个拙劣的可憎

类:
  • 启用键值点访问。
  • 接受defaultsNamespace/Dataclass作为包含默认值的额外参数。
  • 点访问时执行修改后的get(),方法是检查是否可以在defaults中找到默认值,否则返回None

此外,该类应该递归地将初始化时在其值中找到的任何dict以及每个新值转换为Dotdict

下面是它的外观:

class DotDict(dict):
def __init__(self, base_dict=None, defaults=None):
self.defaults = defaults if defaults is not None else SimpleNamespace()
base_dict = base_dict if base_dict is not None else {}
super().__init__(**base_dict)
for key, value in base_dict.items():
self[key] = self._convert(value)
def __getattr__(self, key):
if key in self:
return self[key]
elif hasattr(self.defaults, key):
return getattr(self.defaults, key)
else:
return None
def __setattr__(self, key, value):
self[key] = value
def __delattr__(self, key):
try:
del self[key]
except KeyError as error:
raise AttributeError(error)
def _convert(self, element):
if isinstance(element, dict):
return DotDict(
{key: self._convert(value) for key, value in element.items()},
defaults=self.defaults,
)
elif isinstance(element, list):
return [self._convert(subelement) for subelement in element]
else:
return element

尽管它可能违背了所有常识和大约十几种最佳实践,但事情确实有效 - 除了一个细节:我还没有找到一种方法来分配 dedefault属性而不将其添加到实例的items()中。这是有道理的,因为__setattr__方法会立即被其点访问版本覆盖。

为清楚起见进行了编辑

上述段落的措辞如此糟糕,以至于实际上提出了错误的问题。我知道有几种方法可以在不诉诸类自己的__setattr__的情况下分配属性,正如user2357112 supports Monica所指出的那样,这确实可以解决这个特定问题。

上面描述的代码是为了说明导致我问自己这篇文章的实际问题的过程。 现在用新鲜的眼光阅读整件事让我意识到,原始问题的大多数细节充其量是不必要的,而且可能令人困惑。为了透明起见,我会留给它,但如果我要从头开始重写这个问题,它只会是:

初始化实例,有没有办法覆盖任何类方法?

如果要使用标准__setattr__,只需使用标准__setattr__

object.__setattr__(self, 'defaults', defaults)

其他选项包括通过supersuper().__setattr__('defaults', defaults)调用它或使用self.__dict__['defaults'] = defaults手动将属性粘贴到self.__dict__中。

相关内容

最新更新