I would say the best way to understand how a function is operating is tracing its variable thorugh its execution:
def subsets(nums):
def helper(subset, i):
print( "| "*i + "*"*90)
print( "| "*i + "*{:^88}*".format("STARTING OF helper (i={})".format(i)))
print( "| "*i + "*{:^88}*".format('res= {}, subset = {}'.format( res,subset,len(nums))))
print( "| "*i + "*{:^88}*".format(' '))
if i == len(nums):
print( "| "*i + "*{:^88}*".format('APPENDING "{}" to res'.format( (subset[:]))))
res.append(subset[:])
else:
helper(subset, i+1)
print( "| "*i + "*{:^88}*".format('INTERMEDIATE STEP'.format( res)))
print( "| "*i + "*{:^88}*".format('APPENDING "{}" to subset'.format( nums[i])))
subset.append(nums[i])
helper(subset, i+1)
print( "| "*i + "*{:^88}*".format('INTERMEDIATE STEP'.format( res)))
print( "| "*i + "*{:^88}*".format('REMOVING "{}" from subset'.format( nums[i])))
subset.remove(nums[i])
print( "| "*i + "*{:^88}*".format('res={}'.format( res)))
print( "| "*i + "*{:^88}*".format('END OF helper (i={})'.format( i)))
print( "| "*i + "*"*90)
print( "| "*i + " "*90)
print( "| "*i + " "*90)
res = []
helper([], 0)
return res
print(subsets(["a","b","c"]))
which will produce
******************************************************************************************
* STARTING OF helper (i=0) *
* res= [], subset = [] *
* *
| ******************************************************************************************
| * STARTING OF helper (i=1) *
| * res= [], subset = [] *
| * *
| | ******************************************************************************************
| | * STARTING OF helper (i=2) *
| | * res= [], subset = [] *
| | * *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [], subset = [] *
| | | * *
| | | * APPENDING "[]" to res *
| | | * res=[[]] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * APPENDING "c" to subset *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [[]], subset = ['c'] *
| | | * *
| | | * APPENDING "['c']" to res *
| | | * res=[[], ['c']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * REMOVING "c" from subset *
| | * res=[[], ['c']] *
| | * END OF helper (i=2) *
| | ******************************************************************************************
| |
| |
| * INTERMEDIATE STEP *
| * APPENDING "b" to subset *
| | ******************************************************************************************
| | * STARTING OF helper (i=2) *
| | * res= [[], ['c']], subset = ['b'] *
| | * *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [[], ['c']], subset = ['b'] *
| | | * *
| | | * APPENDING "['b']" to res *
| | | * res=[[], ['c'], ['b']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * APPENDING "c" to subset *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [[], ['c'], ['b']], subset = ['b', 'c'] *
| | | * *
| | | * APPENDING "['b', 'c']" to res *
| | | * res=[[], ['c'], ['b'], ['b', 'c']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * REMOVING "c" from subset *
| | * res=[[], ['c'], ['b'], ['b', 'c']] *
| | * END OF helper (i=2) *
| | ******************************************************************************************
| |
| |
| * INTERMEDIATE STEP *
| * REMOVING "b" from subset *
| * res=[[], ['c'], ['b'], ['b', 'c']] *
| * END OF helper (i=1) *
| ******************************************************************************************
|
|
* INTERMEDIATE STEP *
* APPENDING "a" to subset *
| ******************************************************************************************
| * STARTING OF helper (i=1) *
| * res= [[], ['c'], ['b'], ['b', 'c']], subset = ['a'] *
| * *
| | ******************************************************************************************
| | * STARTING OF helper (i=2) *
| | * res= [[], ['c'], ['b'], ['b', 'c']], subset = ['a'] *
| | * *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [[], ['c'], ['b'], ['b', 'c']], subset = ['a'] *
| | | * *
| | | * APPENDING "['a']" to res *
| | | * res=[[], ['c'], ['b'], ['b', 'c'], ['a']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * APPENDING "c" to subset *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [[], ['c'], ['b'], ['b', 'c'], ['a']], subset = ['a', 'c'] *
| | | * *
| | | * APPENDING "['a', 'c']" to res *
| | | * res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * REMOVING "c" from subset *
| | * res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']] *
| | * END OF helper (i=2) *
| | ******************************************************************************************
| |
| |
| * INTERMEDIATE STEP *
| * APPENDING "b" to subset *
| | ******************************************************************************************
| | * STARTING OF helper (i=2) *
| | * res= [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']], subset = ['a', 'b'] *
| | * *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | * res= [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']], subset = ['a', 'b'] *
| | | * *
| | | * APPENDING "['a', 'b']" to res *
| | | * res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * APPENDING "c" to subset *
| | | ******************************************************************************************
| | | * STARTING OF helper (i=3) *
| | | *res= [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b']], subset = ['a', 'b', 'c']*
| | | * *
| | | * APPENDING "['a', 'b', 'c']" to res *
| | | * res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']] *
| | | * END OF helper (i=3) *
| | | ******************************************************************************************
| | |
| | |
| | * INTERMEDIATE STEP *
| | * REMOVING "c" from subset *
| | * res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']] *
| | * END OF helper (i=2) *
| | ******************************************************************************************
| |
| |
| * INTERMEDIATE STEP *
| * REMOVING "b" from subset *
| * res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']] *
| * END OF helper (i=1) *
| ******************************************************************************************
|
|
* INTERMEDIATE STEP *
* REMOVING "a" from subset *
* res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']] *
* END OF helper (i=0) *
******************************************************************************************
[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]
For a more in-depth explanation, helper as you can see will start executing with an empty list at level 0.
For every level of helper lower than len(nums) the recursive function will branch into 2 new recursive function that will either keep subset as is or add the ith element of nums to it.
For the last level, subset will be added to the result it can be easly visualized with some ascii art graph
nums = ['a','b','c']
level: 0='a' 1='b' 2='c' 3=add_to_res
[] ---> [] -----> [] ---------> []
| | |__________> ['c']
| |
| |______> ['b'] ------> ['b']
| |__________> ['b','c']
|
|____> ['a'] --> ['a'] ------> ['a']
| |__________> ['a','c']
|
|____> ['a','b'] --> ['a','b']
|__________> ['a','b','c']
From a more math oriented point of view you can consider this starting from the last iteration:
- Take cross-producat of the set [[],'c'] with [[],'b'] = [[],'b','c',['b','c']]
- Than take the cross-product of the result with [[],'a'] = [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]