from functools import partial, reduce from testutils import assert_raises class Squares: def __init__(self, max): self.max = max self.sofar = [] def __len__(self): return len(self.sofar) def __getitem__(self, i): if not 0 <= i < self.max: raise IndexError n = len(self.sofar) while n <= i: self.sofar.append(n * n) n += 1 return self.sofar[i] def add(a, b): return a + b assert reduce(add, ["a", "b", "c"]) == "abc" assert reduce(add, ["a", "b", "c"], str(42)) == "42abc" assert reduce(add, [["a", "c"], [], ["d", "w"]], []) == ["a", "c", "d", "w"] assert reduce(add, [["a", "c"], [], ["d", "w"]], []) == ["a", "c", "d", "w"] assert reduce(lambda x, y: x * y, range(2, 21), 1) == 2432902008176640000 assert reduce(add, Squares(10)) == 285 assert reduce(add, Squares(10), 0) == 285 assert reduce(add, Squares(0), 0) == 0 assert reduce(42, "1") == "1" assert reduce(42, "", "1") == "1" with assert_raises(TypeError): reduce() with assert_raises(TypeError): reduce(42, 42) with assert_raises(TypeError): reduce(42, 42, 42) class TestFailingIter: def __iter__(self): raise RuntimeError with assert_raises(RuntimeError): reduce(add, TestFailingIter()) assert reduce(add, [], None) == None assert reduce(add, [], 42) == 42 class BadSeq: def __getitem__(self, index): raise ValueError with assert_raises(ValueError): reduce(42, BadSeq()) # Test reduce()'s use of iterators. class SequenceClass: def __init__(self, n): self.n = n def __getitem__(self, i): if 0 <= i < self.n: return i else: raise IndexError assert reduce(add, SequenceClass(5)) == 10 assert reduce(add, SequenceClass(5), 42) == 52 with assert_raises(TypeError): reduce(add, SequenceClass(0)) assert reduce(add, SequenceClass(0), 42) == 42 assert reduce(add, SequenceClass(1)) == 0 assert reduce(add, SequenceClass(1), 42) == 42 d = {"one": 1, "two": 2, "three": 3} assert reduce(add, d) == "".join(d.keys()) p = partial(add) try: del p.__dict__ assert False, "TypeError expected for partial dict deletion" except TypeError: pass