Lisp mentality vs. Python mentality

bearophileHUGS at lycos.com bearophileHUGS at lycos.com
Sun Apr 26 09:40:38 EDT 2009


Arnaud Delobelle:
> You don't want to silence TypeErrors that may arise from with key() when
> x or y is not a Guard, as it could hide bugs in key(). So I would write
> something like this:
>
> def equal_items(iter1, iter2, key=lambda x: x, _fill = object()):
>     for x, y in izip_longest(iter1, iter2, fillvalue=_fill):
>         if x is _fill or y is _fill or key(x) != key(y):
>             return False
>     return True
>
> (untested)

You are right, thank you. Darn exceptions. You are often able to find
bugs in my code.

Here is a new version then (this is designed to be usable in practice,
that's why it's longer):


from itertools import izip_longest

def equal_iter(iter1, iter2, key=None):
    """
    >>> equal_iter([1, 2], [1, 2, 3])
    False
    >>> equal_iter([1, 2, 3], [1, 2, 3])
    True
    >>> equal_iter([1, 2, 3], [1, -2, 3])
    False
    >>> equal_iter([1, 2, 3], [1, -2, 3], abs)
    True
    >>> equal_iter([1, 2, 3], [1, -2, 4], abs)
    False
    >>> L1, L2 = ["hello", "HALLO"], ["hello", "hallo"]
    >>> equal_iter(L1, L2)
    False
    >>> equal_iter(L1, L2, str.lower)
    True
    >>> equal_iter(xrange(3), (i for i in xrange(3)))
    True
    >>> equal_iter([0, 1, 2], (i for i in xrange(3)))
    True
    >>> equal_iter([0, 1, 2, 3], (i for i in xrange(3)))
    False
    >>> equal_iter([-0, -1, -2], (i for i in xrange(3)), key=abs)
    True
    >>> equal_iter([-0, -1, -2, -3], (i for i in xrange(3)), key=abs)
    False
    >>> x = []
    >>> equal_iter( (x for i in range(3)), (x for i in range(3)) )
    True
    >>> equal_iter( (x for i in range(3)), (x for i in range(4)) )
    False
    >>> equal_iter( (x for i in range(3)), (x for i in range(3)),
key=id)
    True
    >>> equal_iter( (x for i in range(3)), (x for i in range(4)),
key=id)
    False
    >>> equal_iter( (x for i in range(3)), (x for i in range(3)),
key=lambda x:x)
    True
    >>> equal_iter( (x for i in range(3)), (x for i in range(4)),
key=lambda x:x)
    False
    >>> # bug found by Arnaud Delobelle
    >>> def k(x): raise TypeError
    >>> equal_iter( (x for i in range(3)), (x for i in range(3)),
key=k)
    Traceback (most recent call last):
      ...
    TypeError
    """
    try:
        len_iter1 = len(iter1)
        len_iter2 = len(iter2)
    except TypeError:
        pass
    else:
        if len_iter1 != len_iter2:
            return False

    class Guard(object): pass
    guard = Guard()

    if key is None:
        for x, y in izip_longest(iter1, iter2, fillvalue=guard):
            if x != y:
                return False
    else:
        for x, y in izip_longest(iter1, iter2, fillvalue=guard):
            if x is guard or y is guard or key(x) != key(y):
                return False

    return True


if __name__ == "__main__":
    import doctest
    doctest.testmod()
    print "Doctests finished.\n"

Bye,
bearophile



More information about the Python-list mailing list