for more fun--and to yield results that are more variable and less obviously deterministic--we could also use python' random module of to randomly shuffle the sequence to be permuted before the permuter begins its work (in factwe might be able to use the random shuffler as permutation generator in generalas long as we either can assume that it won' repeat shuffles during the time we consume themor test its results against prior shuffles to avoid repeats--and hope that we do not live in the strange universe where random sequence repeats the same result an infinite number of times!in the followingeach permute and next call returns immediately as beforebut permute hangsimport random math factorial( seq list(range( )permute is not an option here random shuffle(seqshuffle sequence randomly first permute (seqnext( [ next( [ random shuffle(seqp permute (seqnext( [ next( [ the main point here is that generators can sometimes produce results from large solution sets when list builders cannot then againit' not clear how common such use cases may be in the real worldand this doesn' necessarily justify the implicit flavor of value generation that we get with generator functions and expressions as we'll see in part vivalue generation can also be coded as iterable objects with classes class-based iterables can produce items on request tooand are far more explicit than the magic objects and methods produced for generator functions and expressions part of programming is finding balance among tradeoffs like theseand there are no absolute rules here while the benefits of generators may sometimes justify their usemaintainability should always be top priority too like comprehensionsgenerators also offer an expressiveness and code economy that' hard to resist if you understand how they work--but you'll want to weigh this against the frustration of coworkers who might not comprehensions and generations