Immutable/Frozen 具有固定键值类型的字典子类
Immutable/Frozen Dictionary subclass with fixed key, value types
问题
类似于previous questions,我想创建一个frozen/immutable字典。具体来说,初始化后,用户在尝试使用 __delitem__
和 __setitem__
方法时应该得到一个 ValueError
。
与前面的问题不同,我特别希望它是一个子class,其中初始化类型被限制为特定的键和值类型。
尝试的解决方案
我自己在 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.
因为.
不合格的备选方案
因为我需要一个subclass,所以commonly suggested solution of using MappingProxyType
不符合我的要求。
此外,我对推荐 subclassing dict
的答案表示怀疑,因为这似乎会导致一些 unintended behaviour.
这对我来说似乎工作得很好(用 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.
我会用 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
>>>
问题
类似于previous questions,我想创建一个frozen/immutable字典。具体来说,初始化后,用户在尝试使用 __delitem__
和 __setitem__
方法时应该得到一个 ValueError
。
与前面的问题不同,我特别希望它是一个子class,其中初始化类型被限制为特定的键和值类型。
尝试的解决方案
我自己在 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.
因为
不合格的备选方案
因为我需要一个subclass,所以commonly suggested solution of using MappingProxyType
不符合我的要求。
此外,我对推荐 subclassing dict
的答案表示怀疑,因为这似乎会导致一些 unintended behaviour.
这对我来说似乎工作得很好(用 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.
我会用 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
>>>