Generating all permutations of a sequence import itertools

def permutation_lib(iterable):
    return itertools.permutations(iterable)


def permutation(iterable):
    if len(iterable) &lt;= 1:
        yield tuple(iterable)
    else:
        for sequence in permutation(iterable[:-1]):
            for i in range(len(sequence)+1):
                yield insert_at(sequence, i, iterable[-1])


def insert_at(iterable, idx, value):
    if idx == 0:
        return (value,) + iterable[:]
    elif idx == len(iterable):
        return iterable[:] + (value,)
    else:
        return iterable[:idx] + (value,) + iterable[idx:]


import unittest


class TestPermutation(unittest.TestCase):
    def test_permutations(self):
        self.assertEqual(list(permutation([0])), list(permutation_lib([0])))
        self.assertEqual(sorted(list(permutation([0,1]))), list(permutation_lib([0, 1])))

if __name__ == '__main__':
    unittest.main()
Imports should always be at the top of the file. I would make an exception for those that are needed only if __name__ == '__main__', but in that case they should be within that block. So your code should look like:

import itertools

def permutation_lib(iterable):
   ...

def permutation(iterable):
    ...

def insert_at(iterable, idx, value):
    ...

if __name__ == '__main__':

    import unittest

    class TestPermutation(unittest.TestCase):
        ...

    unittest.main()


which also means that when you import from this script you don't get the test class, or have import unittest at the top with import itertools.



None of your functions/classes/methods have docstrings. Including these to explain what each one does, and even document the parameters, return values, etc. (I like the Google style for this) makes your code easier to follow.



You have one test method with two assertions covering three functions. Does this not seem odd to you? If that method fails, where do you look for the problem? I would suggest factoring out permutation_lib entirely (which also means you can move import itertools to the testing block) and testing insert_at on its own in a separate method.