If your goal is to turn your nested for loop into a simple recursive function, you've done that successfully. There are some bugs (bad indentation, not returning anything in the second recursive case, …), but the basic structure is sound.
Unfortunately, recursive functions are bounded by the depth of the stack. Some languages have tail call elimination, which means tail-recursive functions aren't bounded. And your implementation is tail-recursive. But Python (intentionally) does not have that feature, so that doesn't matter; you can still only deal with strings up to sys.getrecursionlimit()+1
in length.
If your strings are bounded, but just a little too big for the default recursion limit (which is 1000 in CPython), you can use sys.setrecursionlimit
to set it higher.
There are also tricks to simulate tail call elimination in Python, which I'll discuss below. But even with the best possible trick, your recursive code is still longer, less obvious, less Pythonic, and slower than your nested loop.
If you're doing this for a homework assignment, you're probably done. Unless you were given a choice of programming language, in which case you will need to choose a language with tail call elimination. If you're doing this for real code, you should stick with your original nested loops—the code is simpler, it will run faster, and there is no stack limit, without needing anything hacky or complicated.
The most efficient way to implement tail-call optimization in CPython is by modifying the bytecode of compiled functions, as here. But that's also the hackiest way, and it only works in a restricted set of circumstances.
The simplest way is to modify your function to return a function that returns a value, instead of a value, and then use a trampoline to chain the evaluations together (there are at least two blog posts that show this technique, here and here). But, while that's simplest to implement, it requires changes through your actual recursive functions, which make them more complicated and less readable.
The best tradeoff is probably to use a decorator that inserts a trampoline in the middle of each recursive step, so you don't need to delay function calls explicitly, as seen here. This can get a bit tricky if you have mutually-recursive functions, but it's rarely hard to figure out. And the implementation is pretty easy to understand. And it's not much slower than the bytecode hackery.