π¦ Smart containersΒΆ
Drop-in replacements for dict and list that add type casting, uniqueness and
slicing β while staying ordinary dict/list subclasses you can pass anywhere.
CastedDict β cast keys and values on the way inΒΆ
Give it a key cast and a value cast (either may be None to skip). Every
assignment β including update and construction β is cast eagerly, so what you
store is already the right type:
from python_utils import containers
d = containers.CastedDict(int, int)
d['3'] = '4'
d.update({'5': '6'})
d # {3: 4, 5: 6}
Use the subscription syntax to keep type checkers happy:
d: containers.CastedDict[int, int] = containers.CastedDict(int, int)
LazyCastedDict β cast values only when readΒΆ
Same idea, but values are stored raw and cast on access. Handy when casting is expensive and you only read a subset of the keys. Note that values are not cached, so the cast runs on every read:
from python_utils import containers
d = containers.LazyCastedDict(int, int)
d['3'] = '4'
d.update({'5': '6'})
d # {3: '4', 5: '6'} <- values still raw
d[3] # 4 <- cast on access
list(d.values()) # [4, 6]
UniqueList β a list that rejects duplicatesΒΆ
By default duplicates are silently ignored; set on_duplicate='raise' to turn
them into errors instead. Uniqueness is enforced across append, insert,
extend and item assignment, backed by an internal set for O(1) membership
tests:
from python_utils import containers
u = containers.UniqueList(1, 2, 3)
u.append(2) # ignored
u # [1, 2, 3]
strict = containers.UniqueList(1, 2, 3, on_duplicate='raise')
strict.append(2) # ValueError: Duplicate value: 2
SliceableDeque β a deque you can sliceΒΆ
A collections.deque keeps fast appends and pops at both ends but doesnβt
support slicing. SliceableDeque adds it, plus friendly equality against lists,
tuples and sets:
from python_utils import containers
s = containers.SliceableDeque([1, 2, 3, 4, 5])
s[1:4] # SliceableDeque([2, 3, 4])
s[::-1] # SliceableDeque([5, 4, 3, 2, 1])
s == [1, 2, 3, 4, 5] # True
See the API reference for every method and overload.