Skip to content

Commit e67bf06

Browse files
committed
-
1 parent 319102f commit e67bf06

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

source_py2/python_toolbox/nifty_collections/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .weak_key_default_dict import WeakKeyDefaultDict
99
from .weak_key_identity_dict import WeakKeyIdentityDict
1010
from .lazy_tuple import LazyTuple
11+
from .frozen_dict import FrozenDict
1112

1213
from .emitting_ordered_set import EmittingOrderedSet
1314
from .emitting_weak_key_default_dict import EmittingWeakKeyDefaultDict
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2009-2013 Ram Rachum.
2+
# This program is distributed under the MIT license.
3+
4+
import collections
5+
import operator
6+
7+
8+
class FrozenDict(collections.Mapping):
9+
'''
10+
An immutable `dict`.
11+
12+
A `dict` that can't be changed. The advantage of this over `dict` is mainly
13+
that it's hashable, and thus can be used as a key in dicts and sets.
14+
15+
In other words, `FrozenDict` is to `dict` what `frozenset` is to `set`.
16+
'''
17+
18+
_hash = None # Overridden by instance when calculating hash.
19+
20+
def __init__(self, *args, **kwargs):
21+
self._dict = dict(*args, **kwargs)
22+
23+
__getitem__ = lambda self, key: self._dict[key]
24+
__len__ = lambda self: len(self._dict)
25+
__iter__ = lambda self: iter(self._dict)
26+
27+
def copy(self, *args, **kwargs):
28+
base_dict = self._dict.copy()
29+
base_dict.update(*args, **kwargs)
30+
return type(self)(base_dict)
31+
32+
def __hash__(self):
33+
if self._hash is None:
34+
self._hash = reduce(operator.xor,
35+
map(hash, self.iteritems()),
36+
0) ^ len(self)
37+
38+
return self._hash
39+
40+
__repr__ = lambda self: '<FrozenDict %s>' % repr(self._dict)
41+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright 2009-2013 Ram Rachum.
2+
# This program is distributed under the MIT license.
3+
4+
'''Testing module for `python_toolbox.nifty_collections.LazyTuple`.'''
5+
6+
import uuid
7+
import itertools
8+
import collections
9+
10+
from python_toolbox import cute_iter_tools
11+
from python_toolbox import sequence_tools
12+
from python_toolbox import cute_testing
13+
14+
15+
from python_toolbox.nifty_collections import FrozenDict
16+
17+
18+
def test():
19+
frozen_dict = FrozenDict({'1': 'a', '2': 'b', '3': 'c',})
20+
assert len(frozen_dict) == 3
21+
assert set(frozen_dict) == set(frozen_dict.keys()) == \
22+
set(frozen_dict.iterkeys()) == set('123')
23+
assert set(frozen_dict.values()) == \
24+
set(frozen_dict.itervalues()) == set('abc')
25+
assert set(frozen_dict.items()) == \
26+
set(frozen_dict.iteritems()) == {('1', 'a'), ('2', 'b'), ('3', 'c'),}
27+
assert frozen_dict['1'] == 'a'
28+
with cute_testing.RaiseAssertor(exception_type=LookupError):
29+
frozen_dict['missing value']
30+
assert {frozen_dict, frozen_dict} == {frozen_dict}
31+
assert {frozen_dict: frozen_dict} == {frozen_dict: frozen_dict}
32+
assert isinstance(hash(frozen_dict), int)
33+
34+
assert frozen_dict.copy({'meow': 'frrr'}) == \
35+
frozen_dict.copy(meow='frrr') == \
36+
FrozenDict({'1': 'a', '2': 'b', '3': 'c', 'meow': 'frrr',})
37+

0 commit comments

Comments
 (0)