Python:如何禁用在属性字典中创建新键?

Posted

技术标签:

【中文标题】Python:如何禁用在属性字典中创建新键?【英文标题】:Python: how to disable creation of new keys in attribute dict? 【发布时间】: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://***.com/a/14620633/1179925

我可以像这样使用它:

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

我希望这成为可能:

d.b = 10
print(d)

但我希望这是不可能的:

d.c = 4
print(d)

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

【问题讨论】:

你为什么不创建一个包含字典的对象。这样就无法添加新属性,但可以更改现有属性。 Prevent creating new attributes outside __init__的可能重复 也看看这里:***.com/questions/39440190/… @Chognificent Class in python 不保证这一点。 【参考方案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,然后在特殊方法中检查是否设置或不设置值以检查键是否在字典中。因此允许您最初设置字典,但之后不能设置 这个答案好像用了这个方法***.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。

【讨论】:

以上是关于Python:如何禁用在属性字典中创建新键?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Python中创建一个递归函数来创建一个映射Odoo 8关系字段记录的字典?

如何使用 scala/python/spark 在 CSV 文件中创建新的时间戳(分钟)列

根据附加的字典列表在 df 中创建新列并遍历字典 Pandas 列表

如何在 python+numpy/pandas 中使用二值化在 json 文件中创建新列

在sailsjs中创建新模型后可以更新属性吗?

无法在 Vue.js(laravel 项目)中创建新的实例属性