【问题标题】:Immutable/Frozen Dictionary subclass with fixed key, value types具有固定键、值类型的不可变/冻结字典子类
【发布时间】:2021-02-03 23:16:21
【问题描述】:

问题

类似于previous questions,我想创建一个冻结/不可变字典。具体来说,初始化后,用户在尝试使用__delitem____setitem__ 方法时应该得到一个ValueError

与前面的问题不同,我特别希望它是一个子类,其中初始化类型被限制为特定的键和值类型。

尝试的解决方案

我自己在accomplishing this with collections.UserDict 的尝试失败了:

class WorkflowParams(UserDict):
    def __init__(self, __dict: Mapping[str, str]) -> None:
        super().__init__(__dict=__dict)

    def __setitem__(self, key: str, item: str) -> None:
        raise AttributeError("WorkflowParams is immutable.")

    def __delitem__(self, key: str) -> None:
        raise AttributeError("WorkflowParams is immutable.")

尝试使用时:

workflow_parameters = WorkflowParams(
    {
        "s3-bucket": "my-big-bucket",
        "input-val": "1",
    }
)

失败了

Traceback (most recent call last):
  File "examples/python_step/python_step.py", line 38, in <module>
    workflow_parameters = WorkflowParams(
  File "/home/sean/git/scargo/scargo/core.py", line 14, in __init__
    super().__init__(__dict=__dict)
  File "/home/sean/miniconda3/envs/scargo/lib/python3.8/collections/__init__.py", line 1001, in __init__
    self.update(kwargs)
  File "/home/sean/miniconda3/envs/scargo/lib/python3.8/_collections_abc.py", line 832, in update
    self[key] = other[key]
  File "/home/sean/git/scargo/scargo/core.py", line 17, in __setitem__
    raise AttributeError("WorkflowParams is immutable.")
AttributeError: WorkflowParams is immutable.

因为how __init__() resolves methods

不合格的替代品

由于我需要一个子类,commonly suggested solution of using MappingProxyType 不符合我的要求。

此外,我怀疑建议子类化dict 的答案,因为这似乎会导致一些unintended behaviour

【问题讨论】:

  • 好吧,无论你传递给 `super().__init__(__dict=__dict)` 最终都会调用 __setitem__,为什么不直接在 __init__ 中使用 @987654339 手动执行此操作@?
  • @juanpa.arrivillaga 不知何故,这也行不通。 super().__setitem__(key, __dict[key]) 仍然调用我的子类'__setitem__
  • 噢,是的,因为它是一种抽象方法。我的意思是,只需使用self.data[key] = value
  • @juanpa.arrivillaga self.data 不是类属性,所以在调用UserDict.__init()__ 之前它不存在。
  • 我只是尝试调用 super().__setitem__() 作为构造函数的一部分,这一切似乎都按预期工作。你能建议什么 Python 版本似乎不起作用吗?另外你为什么不想调用 UserDict.__init__()?

标签: python python-3.x dictionary data-structures immutability


【解决方案1】:

这对我来说似乎工作得很好(用 Python 3.6 和 3.8 测试):

from collections import UserDict
from typing import Mapping


class WorkflowParams(UserDict):
    def __init__(self, __dict: Mapping[str, str]) -> None:
        super().__init__()
        for key, value in __dict.items():
            super().__setitem__(key, value)

    def __setitem__(self, key: str, item: str) -> None:
        raise AttributeError("WorkflowParams is immutable.")

    def __delitem__(self, key: str) -> None:
        raise AttributeError("WorkflowParams is immutable.")


workflow_parameters = WorkflowParams(
    {
        "s3-bucket": "my-big-bucket",
        "input-val": "1",
    }
)

print(workflow_parameters)
# output: {'s3-bucket': 'my-big-bucket', 'input-val': '1'}

workflow_parameters['test'] = 'dummy'
# expected exception: AttributeError: WorkflowParams is immutable.

【讨论】:

    【解决方案2】:

    我会用 collections.abc 来做,它只是为了快速构建容器类,只需实现几件事并完成

    >>> import collections
    >>> class FrozenDict(collections.abc.Mapping):
    
        def __init__(self,/,*argv,**karg):
            self._data = dict(*argv,**karg)
    
        def __getitem__(self,key):
            return self._data[key]
    
        def __iter__(self):
            return iter(self._data)
    
        def __len__(self):
            return len(self._data)
    
        def __repr__(self):
            return f"{type(self).__name__}({self._data!r})"
    
        
    >>> t=FrozenDict( {
            "s3-bucket": "my-big-bucket",
            "input-val": "1",
        })
    >>> t
    FrozenDict({'s3-bucket': 'my-big-bucket', 'input-val': '1'})
    >>> t["test"]=23
    Traceback (most recent call last):
      File "<pyshell#38>", line 1, in <module>
        t["test"]=23
    TypeError: 'FrozenDict' object does not support item assignment
    >>> del t["input-val"]
    Traceback (most recent call last):
      File "<pyshell#39>", line 1, in <module>
        del t["input-val"]
    TypeError: 'FrozenDict' object does not support item deletion
    >>> 
    

    【讨论】:

      猜你喜欢
      • 2021-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-15
      • 2018-11-05
      • 1970-01-01
      • 2018-12-04
      相关资源
      最近更新 更多