rsdict is a restricted and resetable dictionary,
a subclass of dict
(inherits from built-in dictionary).
>>> from rsdict import rsdict
>>> d = {"foo": 0, "bar": "baz"}
>>> rd = rsdict(d)
>>> rd
rsdict({'foo': 0, 'bar': 'baz'}, frozen=False, fixkey=True, fixtype=True, cast=False)
# fixkey=True: key restriction
>>> rd["newkey"] = 1
AttributeError
# fixtype=True: type restriction
>>> rd["foo"] = "str.value"
TypeError
>>> rd["foo"] = 999
>>> rd == d
False
# reset values to initial
>>> rd.reset()
>>> rd == d
True
pip install rsdict
- Type-restrict(able): If activated, every type of value is fixed to its initial type.
- Key-restrict(able): If activated, cannot add or delete keys.
- Resettable: to initial value(s).
rsdict(items, frozen=False, fixkey=True, fixtype=True, cast=False)
- items (dict): Initial items (data). Built-in dictionary only. kwargs are not supported.
- frozen (bool, optional): If True, the instance will be frozen (immutable).
- fixkey (bool, optional): If True, cannot add or delete keys.
- fixtype (bool, optional): If True, cannot change type of keys.
- cast (bool, optional): If False, cast to initial type (if possible). If True, allow only the same type of initial value.
# rsdict(frozen=True) as default
from rsdict import rsdict_frozen as rsdict
# rsdict(fixkey=False, fixtype=False) as default
from rsdict import rsdict_unfix as rsdict
# rsdict(fixkey=True, fixtype=False) as default
from rsdict import rsdict_fixkey as rsdict
# rsdict(fixkey=False, fixtype=True) as default
from rsdict import rsdict_fixtype as rsdict
set(key, value)
: Alias of__setitem__
.to_dict() -> dict
: Convert to dict instance.reset(key: Optional[Any]) -> None
: Reset value to the initial value. If key is None, reset all values.is_changed(key: Optional[Any]) -> bool
: If True, the values are changed from initial. If key is not None, check the key only.get_initial(key: Optional[Any]) -> dict | Any
: Return initial value(s). If key is None, Return dict of all initial values.
>>> from rsdict import rsdict
>>> d = dict(
... name = "John",
... enable = True,
... count = 0,
... )
>>> rd = rsdict(d)
>>> rd
rsdict({'name': 'John', 'enable': True, 'count': 0},
frozen=False, fixkey=True, fixtype=False)
>>> type(rd) is dict
False
>>> isinstance(rd, dict)
True
>>> rd.frozen
False
Same as dict
.
>>> rd["count"] == d["count"]
True
>>> rd["xyz"]
KeyError
>>> rd.get("count") == d.get("count")
True
>>> rd.get("xyz")
None
>>> rd["enable"] = False
>>> rd.set("enable", False)
# If frozen, always raise an exception.
>>> rd_frozen = rsdict(d, frozen=True)
>>> rd_frozen["count"] = 2
AttributeError
# If fixtype and not cast, different-type value raise an exception.
>>> rd["count"] = "2"
TypeError
# If fixtype and cast, cast value to initial type.
>>> rd_cast = rsdict(d, cast=True)
>>> rd_cast["count"] = "2"
>>> rd_cast["count"]
2
>>> rd_cast["count"] = "abc"
ValueError
# If not fixtype, anything can be set.
>>> rd_typefree = rsdict(d, fixtype=False)
>>> rd_typefree["count"] = "2"
>>> rd_typefree["count"]
'2'
# If fixkey, setting with a new key raises an exception.
>>> rd["location"] = 9
AttributeError
# If not fixkey, a new key can be set.
>>> rd_keyfree = rsdict(d, fixkey=False)
>>> rd_keyfree["location"] = 9
>>> rd_keyfree["location"]
9
# If frozen or fixkey, deleting key raises an exception.
>>> del rd["count"]
AttributeError
# Else, delete both current and initial values.
>>> rd_keyfree = rsdict(dict(a=1, b=2, c=3), fixkey=False)
>>> del rd_keyfree["b"]
>>> rd_keyfree.keys()
dict_keys(['a', 'c'])
>>> rd_keyfree.get_initial().keys()
dict_keys(['a', 'c'])
# Check whether the values are changed from initial.
>>> rd.is_changed()
False
# (Change some values.)
>>> rd["enable"] = False
>>> rd["count"] = 5
>>> rd.is_changed()
True
# Reset with a key.
>>> rd.reset("count")
>>> rd["count"]
0
>>> rd.is_changed()
True
# Reset all values.
>>> rd.reset()
>>> rd.is_changed()
False
# Create a new rsdict with different optional arguments.
# If reset, copy initial values only.
>>> rd["name"] = "Mike"
>>> rd2 = rd.copy(reset=True)
>>> rd2 == rd.get_initial()
True
# If frozen and not reset, copy current values as new initial values.
>>> rd3 = rd.copy(frozen=True)
>>> rd3
rsdict({'name': 'Mike', 'enable': True, 'count': 0},
frozen=True, fixkey=True, fixtype=False, cast=False)
>>> rd3 == rd
True
>>> rd3.get_initial() == rd.get_initial()
False
>>> rd1 = rsdict({"key1": 10, "key2": "abc"})
>>> rd2 = rsdict({"key1": 20, "key2": "abc"})
# Change current value.
>>> rd2["key1"] = 10
# Current values are equal.
>>> rd1 == rd2
True
# Initial values are not equal.
>>> rd1.get_initial() == rd2.get_initial()
False
# If compare with dict, use current values.
>>> d2 = rd2.to_dict()
>>> rd2 == d2
(Python3.9 or later)
>>> rd = rsdict({"key1": 10, "key2": "abc"}, fixkey=False)
>>> d = {"key2": 20, "key3": False}
# Return: dict
>>> rd | d
{'key1': 10, 'key2': 20, 'key3': False}
>>> d | rd
{'key2': 'abc', 'key3': False, 'key1': 10}
>>> rd |= d
>>> rd
rsdict({'key1': 10, 'key2': 20, 'key3': False},
frozen=False, fixkey=False, fixtype=True, cast=False)
# Add initial values of new keys only.
>>> rd.get_initial()
{'key1': 10, 'key2': 'abc', 'key3': False}
- Expected types of value:
int
,float
,str
,bool
,None
,list
,dict
,tuple
,pathlib.Path
- Some types (e.g.
numpy.ndarray
) cannot be cast. - Tested in Python3.5, 3.6, 3.7, 3.8, 3.9, 3.10.
- Only initial items are deepcopied.
>>> d = dict(a=[1])
>>> rd = rsdict(d)
>>> rd["a"].append(2)
>>> rd
rsdict({'a': [1, 2]}, frozen=False, fixkey=True, fixtype=True, cast=False)
>>> d
{'a': [1, 2]}
>>> rd.get_initial()
{'a': [1]}
rsdict is slower than dict
due to its additional checking.
-> CHANGELOG.md