/usr/lib/python3/dist-packages/toolz/sandbox/core.py is in python3-toolz 0.8.2-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | from toolz.itertoolz import getter, cons, pluck
from itertools import tee, starmap
# See #166: https://github.com/pytoolz/toolz/issues/166
# See #173: https://github.com/pytoolz/toolz/pull/173
class EqualityHashKey(object):
""" Create a hash key that uses equality comparisons between items.
This may be used to create hash keys for otherwise unhashable types:
>>> from toolz import curry
>>> EqualityHashDefault = curry(EqualityHashKey, None)
>>> set(map(EqualityHashDefault, [[], (), [1], [1]])) # doctest: +SKIP
{=[]=, =()=, =[1]=}
**Caution:** adding N ``EqualityHashKey`` items to a hash container
may require O(N**2) operations, not O(N) as for typical hashable types.
Therefore, a suitable key function such as ``tuple`` or ``frozenset``
is usually preferred over using ``EqualityHashKey`` if possible.
The ``key`` argument to ``EqualityHashKey`` should be a function or
index that returns a hashable object that effectively distinguishes
unequal items. This helps avoid the poor scaling that occurs when
using the default key. For example, the above example can be improved
by using a key function that distinguishes items by length or type:
>>> EqualityHashLen = curry(EqualityHashKey, len)
>>> EqualityHashType = curry(EqualityHashKey, type) # this works too
>>> set(map(EqualityHashLen, [[], (), [1], [1]])) # doctest: +SKIP
{=[]=, =()=, =[1]=}
``EqualityHashKey`` is convenient to use when a suitable key function
is complicated or unavailable. For example, the following returns all
unique values based on equality:
>>> from toolz import unique
>>> vals = [[], [], (), [1], [1], [2], {}, {}, {}]
>>> list(unique(vals, key=EqualityHashDefault))
[[], (), [1], [2], {}]
**Warning:** don't change the equality value of an item already in a hash
containter. Unhashable types are unhashable for a reason. For example:
>>> L1 = [1] ; L2 = [2]
>>> s = set(map(EqualityHashDefault, [L1, L2]))
>>> s # doctest: +SKIP
{=[1]=, =[2]=}
>>> L1[0] = 2 # Don't do this! ``s`` now has duplicate items!
>>> s # doctest: +SKIP
{=[2]=, =[2]=}
Although this may appear problematic, immutable data types is a common
idiom in functional programming, and``EqualityHashKey`` easily allows
the same idiom to be used by convention rather than strict requirement.
See Also:
identity
"""
__slots__ = ['item', 'key']
_default_hashkey = '__default__hashkey__'
def __init__(self, key, item):
if key is None:
self.key = self._default_hashkey
elif not callable(key):
self.key = getter(key)
else:
self.key = key
self.item = item
def __hash__(self):
if self.key == self._default_hashkey:
val = self.key
else:
val = self.key(self.item)
return hash(val)
def __eq__(self, other):
try:
return (self._default_hashkey == other._default_hashkey and
self.item == other.item)
except AttributeError:
return False
def __ne__(self, other):
return not self.__eq__(other)
def __str__(self):
return '=%s=' % str(self.item)
def __repr__(self):
return '=%s=' % repr(self.item)
# See issue #293: https://github.com/pytoolz/toolz/issues/239
def unzip(seq):
"""Inverse of ``zip``
>>> a, b = unzip([('a', 1), ('b', 2)])
>>> list(a)
['a', 'b']
>>> list(b)
[1, 2]
Unlike the naive implementation ``def unzip(seq): zip(*seq)`` this
implementation can handle a finite sequence of infinite sequences.
Caveats:
* The implementation uses ``tee``, and so can use a significant amount
of auxiliary storage if the resulting iterators are consumed at
different times.
* The top level sequence cannot be infinite.
"""
seq = iter(seq)
# Check how many iterators we need
try:
first = tuple(next(seq))
except StopIteration:
return tuple()
# and create them
niters = len(first)
seqs = tee(cons(first, seq), niters)
return tuple(starmap(pluck, enumerate(seqs)))
|