# Lisp mentality vs. Python mentality

bearophileHUGS at lycos.com bearophileHUGS at lycos.com
Sun Apr 26 15:40:38 CEST 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

```