【问题标题】:Python: how to disable creation of new keys in attribute dict?Python:如何禁用在属性字典中创建新键?
【发布时间】:2020-01-20 10:05:14
【问题描述】:

这里是一个简单的属性dict代码:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self

更多上下文: https://stackoverflow.com/a/14620633/1179925

我可以像这样使用它:

d = AttrDict({'a':1, 'b':2})
print(d)

我希望这成为可能:

d.b = 10
print(d)

但我希望这是不可能的:

d.c = 4
print(d)

是否有可能在创建新密钥时抛出错误?

【问题讨论】:

标签: python dictionary attributes


【解决方案1】:

你可以检查他们是否已经在那里

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__dict__ = self

    def __setattr__(self, key, value):
        if key not in [*self.keys(), '__dict__']:
            raise KeyError('No new keys allowed')
        else:
            super().__setattr__(key, value)

    def __setitem__(self, key, value):
        if key not in self:
            raise KeyError('No new keys allowed')
        else:
            super().__setitem__(key, value)

首先,我认为这是一个坏主意,因为无法添加初始值,但从内置函数中它指出以下内容: dict(iterable) -> 新字典的初始化就像通过: d = {} 对于可迭代的 k,v: d[k] = v

因此,这确实允许您更改方法而不影响 Class 的初始化,因为它从 {} 而不是从它自己的实例创建一个新方法。

尽管如此,他们将能够始终更改 __ dict __..

【讨论】:

  • 你能详细说明为什么我们检查key'__dict__'__setattr__ 吗?
  • 为了让您实际使用 dict 值作为属性,需要 self.__dict__ = self 调用。如果 setattr 中不允许 dict,这将失败。也可以使用某种冻结开关。
  • freeze switch 是什么?
  • 类跟踪它被“冻结”的位置,因此在初始化时它会首先设置一些值“冻结”从 False 到最后的 True,然后在特殊方法中检查是否设置或不设置值以检查键是否在字典中。因此允许您最初设置字典,但之后不能设置
  • 这个答案好像用了这个方法stackoverflow.com/a/58010685/1179925
【解决方案2】:

您可以覆盖__setattr__ 特殊方法。

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super(AttrDict, self).__setattr__('_initializing', True)
        super(AttrDict, self).__init__(*args, **kwargs)
        self.__dict__ = self
        super(AttrDict, self).__setattr__('_initializing', False)

    def __setattr__(self, x, value):
        if x == '_initializing':
            raise KeyError("You should not edit _initalizing")
        if self._initializing or x in self.__dict__.keys():
            super(AttrDict, self).__setattr__(x, value)
        else:
            raise KeyError("No new keys allowed!")

请注意,我需要添加一个属性_initializing 以让__setattr__ 区分__init__ 创建的属性和用户创建的属性。
由于python没有私有属性,用户可能仍然将_initializing设置为True,然后将他们的属性添加到AttrDict实例中,所以我添加了进一步检查以确保他们没有尝试编辑_initializing .
它仍然不是 100% 安全的,因为用户仍然可以使用 super()_initializing 设置为 True。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多