I dislike the answer given before me using product since looking at its implementation in the python documentation it seem to span the entire thing into a list in memory before starting to yield the results.
This is very bad for your case since, as agf himself said, the number of permutation here is huge (well over a million). For this case the yield statement was created - so that huge lists could be dynamically generated rather than spanned in memory (I also disliked the wasteful range where xrange is perfectly applicable).
I'd go for a solution like this:
def generate(chars, length, prefix = None):
if length < 1:
return
if not prefix:
prefix = ''
for char in chars:
permutation = prefix + char
if length == 1:
yield permutation
else:
for sub_permutation in generate(chars, length - 1, prefix = permutation):
yield sub_permutation
This way, all that spans in memory is a recursive stack "n" deep, where "n" is the length of your permutations (4 in this case) and only a single element is returned each time.
chars is the set of chars to choose from, length is 4 and the use is rather similar to products, except that it doesn't span the whole list in memory during run time.