简体   繁体   中英

Help understanding how this recursive python function works?

i'm aa programmer, i do some C# perl and python, anyways, i found this recursive code to generate permutations, of a list of symbols and letters, but i can't figure out how it works? can anyone care to explain it please?

#!/usr/bin/env python
#-*- coding:utf-8 -*-

def generate(charlist,state,position):
    for i in charlist:
        state[position] = i
        if position == (len(state)-1):
            print "".join(state)
        else:
            generate(charlist,state,position+1)

generate("1234567890qwertyuiopasdfghjklzxcvbnm",[None]*8,0)

here is the code, with all correct spacing.

This does not generate permutations. It generates n-dimensional cartesian products. (In the process, it also generates all permutations, but the algorithm to generate only permutations would be different.)

It's a bit difficult to explain how it works, but if you look at the output for small input, you can see what's going on. Consider the output for 'abc' and [None] * 3 (I modified the code to act as a true generator):

>>> def generate(charlist,state,position):
...     for i in charlist:
...         state[position] = i
...         if position == (len(state)-1):
...             yield "".join(state)
...         else:
...             for j in generate(charlist,state,position+1):
...                 yield j
... 
>>> print list(generate('abc', [None] * 3, 0))
['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 
 'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc', 
 'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']

As you can see, what happens is that initially, generate calls itself three times, incrementing position each time (from 0 to 1 to 2 ). Each time through the recursion-loop, it puts 'a' in the current position and tests to see if it has reached the end of the state list. If so, it yields the result and does not call itself.

In this case, when that happens, position == 2 . Now the for loop kicks in, storing 'b' and 'c' in state[2] and yielding each of those states. Then the function ends, and control is returned to the caller, for which position == 1 . The caller then continues through its for loop; it sets state[1] = 'b' and then, since position is no longer at the end of the state list, it calls itself again... now position == 2 and the for loop sets state[2] == 'a' , 'b' , 'c' , and so on.

By the way, if you want to compute cartesian products in python, here's a nice way that doesn't require your readers to parse out a recursive algorithm:

>>> import itertools
>>> [''.join(c) for c in itertools.product('abc', 'abc', 'abc')]
['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 
 'baa', 'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc', 
 'caa', 'cab', 'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']

You could also do

>>> [''.join(c) for c in itertools.product(*['abc'] * 3)]

You can't figure out how it works? Put this line just after the def generate... :

print charlist, state, position

and it will tell you what variables are used at each call.

The function outputs every possible (unless the third argument is non-zero) combination of given characters.

It takes as the input:

  1. a list or string of characters that will be combined,
  2. a list which length denotes how many characters should be combined at once,
  3. a number which denotes how many characters of each combination should be replaced with corresponding characters from the second list (which will reduce the number of possible combinations accordingly).

If the second argument is a list of 8 None values (because [None] * 8 == [None, None, None, None, None, None, None, None] ), setting third argument to non-zero value will cause TypeError .

@senderle's answer explains what happens in the function.

I should say that this is an example of non-Pythonic code, precisely because it's hard to tell its purpose from the first sight.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM