ending condition for recursive function call - python

I am new to python.
The below recursive code works as expected, so far so good.
What I am wondering about is why after 5 "loops" it stops calling itself recursively.
x=0
def factfunc(n):
global x
x+=1
print("loop #:", x, "-> ", end="")
if n < 0:
print("returning 'None'")
return None
if n < 2:
print("returning '1'")
return 1
print ("n=",n)
return n * factfunc(n - 1)
print ("Finally returned:", factfunc(5))
Output:
loop #: 1 -> n= 5
loop #: 2 -> n= 4
loop #: 3 -> n= 3
loop #: 4 -> n= 2
loop #: 5 -> returning '1'
Finally returned: 120
Hints would be appreciated. Thanks.

Not sure if I am supposed to answer my own question, doing it anyway:
Thanks to trincot's comment I believe I have understood now, I think this is what happens:
return 5 x # not returning anything here, instead calling itself again
(return 4 x # not returning anything here, instead calling itself again
(return 3 x # not returning anything here, instead calling itself again
(return 2 x # not returning anything here, instead calling itself again
(return 1) # returning 1 (no more recursive action from now on)
) # returning 1 x 2 = 2
) # returning 2 x 3 = 6
) # returning 6 x 4 = 24
# 'finally' returning 5 x 24 = 120
=> 120
Hope the above is understandable. Thanks again.

Related

How does this function for Hamming numbers work?

I was trying to write a function to generate Hamming numbers and encountered this code on www.w3resource.com.
The code is very easy but I can't seem to understand the order of output values.
def is_hamming_numbers(x):
if x==1:
return True
if x%2==0:
return is_hamming_numbers(x/2)
if x%3==0:
return is_hamming_numbers(x/3)
if x%5==0:
return is_hamming_numbers(x/5)
return False
def hamming_numbers_sequence(x):
if x==1:
return 1
hamming_numbers_sequence(x - 1)
if is_hamming_numbers(x)==True:
print('%s'%x,end=' ')
hamming_numbers_sequence(10)
I expected the output to be:
10 9 8 8 5 4 3 2
The output would be:
2 3 4 5 6 8 9 10
Could anyone please explain why is the order of numbers reversed? I tried to change the order in the code like this:
if is_hamming_numbers(x)==True:
print('%s'%x,end=' ') #this first
hamming_numbers_sequence(x - 1) #then this line
And it would give the output in the order I expected.
def hamming_numbers_sequence(x):
if x==1:
return 1
hamming_numbers_sequence(x - 1) // repeated here
if is_hamming_numbers(x)==True: // means x=2
print('%s'%x,end=' ')
this function hamming_numbers_sequence(x - 1) will repeat it self until reaching x=1 the blocking instruction if x==1: so the second function will enter with the value of x=2 is_hamming_numbers(2)==True:
so you have the out put you're having if you want to change it try it this way
def hamming_numbers_sequence(x):
print('%s'%x,end=' ')
if x==1:
return 1
hamming_numbers_sequence(x - 1)
if is_hamming_numbers(x)==True:
// do what ever you want here

how to read this function

def cat(xx):
if (xx<1):
return 5
if (xx<2):
return 2
if(xx<3):
return 4
if(xx<4):
return 7
if(xx<5):
return 8
if(xx<6):
return 6
if(xx<7):
return 1
if(xx<8):
return 9
if (xx<9):
return 3
else:
return cat(xx-9)
print(cat(38))
the answer python gives me is 4. I am not sure why it gives me this number. I know there are multiple if statements and not elif but I don't know how that causes this answer
The stack call of cat(38) will be:
print(cat(38))
return(cat(38-9))
return(cat(29))
return(cat(20))
return(cat(11))
return(cat(2))
<-- will return 4 since `xx<3` will evaluate to true
The function keeps on substracting 9 to xx until it returns something different from cat(xx-9). When you enter 38 you get 2 by the fourth time you enter the function recursively and then the output is 4
else:
return cat(xx-9)
So because you did print(cat(38)) but there is no if statement when the number is above 9 so it will go to else but what you did was to recall the function instead of returning the number.
Why it gives you 4 every time is because the function is in a loop and it will continue to xx-9 until it finds a valid if statement then it will return the number 4 for example:
38 - 9 = 29, 29 - 9 = 20, 20 - 9 = 11, 11 - 9 = 2 <--- this is what the function is doing.
Solution:
else:
return xx-9

Backtracking to find the maze exit. Why does my function always return True?

My code successfully makes its way through all the possible paths in the maze... but it always returns True, even though true only updates if certain conditions are met (having reached the edge of the maze). It seems I have misunderstanding of scope. This is my first time using the global keyword.
Here's some sample input/output. Above is the maze, the two numbers are (x, y) coordinates of current position in the maze. 'k' is the starting position, '#' is a wall.
# # ## #
# #k# #
# # # ##
# # # #
# ##
########
3 2
3 3
3 4
3 5
4 5
5 5
5 4
6 4
5 3
5 2
6 2
6 1
2 5
1 5
1 4
1 3
1 2
1 1
3 1
True
found = False
def find_start(maze):
start = None
for i in range(len(maze)):
print(maze[i])
for j in range(len(maze[i])):
if maze[i][j] == 'k':
if start == None:
start = (i, j)
else:
raise "There should be no multiple Kates"
if not start:
raise "There should be one Kate"
return start
def has_exit(maze):
visited = [[False for _ in range(len(maze[i]))] for i in range(len(maze))]
y, x = find_start(maze)
def backtrack(maze, x, y):
visited[y][x] = True
print(x, y)
if x == 0 or x == (len(maze[y]) - 1) or y == 0 or y == (len(maze) - 1) or x > len(maze[y+1]) - 1 or x > len(maze[y-1]) - 1: # This last condition is the hard one.
print('Found edge')
global found
found = True
return
if maze[y][x+1] == ' ' and not visited[y][x+1]:
backtrack(maze, x+1, y)
if maze[y][x-1] == ' ' and not visited[y][x-1]:
backtrack(maze, x-1, y)
if maze[y+1][x] == ' ' and not visited[y+1][x]:
backtrack(maze, x, y+1)
if maze[y-1][x] == ' ' and not visited[y-1][x]:
backtrack(maze, x, y-1)
backtrack(maze, x, y)
if found:
print(found)
return True
else:
print(found)
return False
The only place found is assigned a value is the first time through the code =False Then whenever the code hits backtrack it assigns it True. Importantly for your question, you never reset found, so as soon as set to True one time, it will never reset. Since you are recursing over all possible paths, you will hit an edge eventually, so found=True eventually for any run.
I agree with the other suggestions about using return values from functions, but here you just need to reset your state appropriately for the recursive search.
You haven't provided start point for you code to debug further.
However the basic rules for global keyword in Python are:
When we create a variable inside a function, it is local by default.
When we define a variable outside of a function, it is global by
default.You don't have to use global keyword.
We use global keyword
to read and write a global variable inside a function.
Use of global
keyword outside a function has no effect.
Source - More examples are found in this source

Function calling function in python

def one_good_turn(n):
return n + 1
def deserves_another(n):
return one_good_turn(n) + 2
print(one_good_turn(1))
print(deserves_another(2))
Since I have two function one_good_turn(n) and deserves_another(n) while calling function I had passed parameter 1 and 2:
I expected the output to be:
2
4
but its shows:
2
5
Why is the output not what I had expected?
I believe you assume that one_good_turn(n) in deserves_another(n) will return the value that is previously computed. No. It gets the current input n which is 2, call the function again, do 2+1 which is 3. Then you add 3 + 2 = 5.
Maybe to get your desired output, you should pass 1 to deserves_another:
def one_good_turn(n):
return n + 1
def deserves_another(n):
return one_good_turn(n) + 2
print(one_good_turn(1)) # 2
print(deserves_another(1)) # 4
A better way is to return the value from one_good_turn and pass it to deserves_another. So you don't need to call one_good_turn again inside deserves_another:
def one_good_turn(n):
n = n + 1
print(n) # 2
return n
def deserves_another(n):
return n + 2
n = one_good_turn(1)
print(deserves_another(n)) # 4
one_good_turn(2) returns 2+1=3.
Then the result is passed to deserves_another, which returns 3+2=5.

A simple prog in Python. Involves digits of numbers

So basically, this prog reads 5 numbers:
X, Y, startFrom, jump, until
with space separating each number. an example:
3 4 1 1 14
X = 3
Y = 4
1 = startFrom
jump = 1
until = 14
In order to do that, I used:
#get X, Y, startFrom, jump, until
parameters = raw_input()
parametersList = parameters.split()
X = int(parametersList[0])
Y = int(parametersList[1])
#start from startFrom
startFrom = int(parametersList[2])
#jumps of <jump>
jump = int(parametersList[3])
#until (and including) <until>
until = int(parametersList[4])
The program outputs a chain (or however you would like to call it) of, let's call it BOOZ and BANG, when BOOZ is X if exists in the number (i.e X is 2 and we are at 23, so it's a BOOZ) . in order to check that (I used: map(int, str(currentPos)) when my currentPos (our number) at first is basically startFrom, and as we progress (add jump every time), it gets closer and closer to until), or if X divides the currentPos (X%num == 0. i.e: X is 2 and we are at 34, it's also a BOOZ).
BANG is the same, but with Y. If currentPos is both BOOZ & BANG, the output is BOOZ-BANG.
startFrom, startFrom+ jump, startFrom+2*jump, startFrom+3*jump, ..., until
We know the numbers read are int type, but we need to make sure they are valid for the game.
X and Y must be between 1 and 9 included. otherwise, we print (fter all 5 numbers have been read): X and Y must be between 1 and 9 and exit the prog.
In addition, jump can't be 0. if it is, we print jump can't be 0 and exit the prog. Else, if we can't reachuntil using jump jumps (if startFrom+ n * jump == until when n is an int number) so we need to print can't jump from <startFrom> to <until> and exit the prog.
My algorithm got too messy there with alot of ifs and what not, so I'd like an assistance with that as well)
so for our first example (3 4 1 1 14) the output should be:
1,2,BOOZ,BANG,5,BOOZ,7,BANG,BOOZ,10,11,BOOZ-BANG,BOOZ,BANG
another example:
-4 -3 4 0 19
OUTPUT:
X and Y must be between 1 and 9
juump can't be 0
another:
5 3 670 7 691
OUTPUT:
BOOZ,677,BANG,691
another:
0 3 4 -5 24
OUTPUT:
X and Y must be between 1 and 9
can't jump from 4 to 24
another:
3 4 34 3 64
OUTPUT:
BOOZ-BANG,BOOZ,BANG,BOOZ-BANG,BANG,BANG,BANG,55,58,61,BANG
my prog is toooo messy ( I did a while loop with ALOT of ifs.. including if currentPos==until so in that cause it won't print the comma (,) for the last item printed etc.. but like I said, all of it is so messy, and the ifs conditions came out so long and messy that I just removed it all and decided to ask here for a nicer solution.
Thanks guys
I hope it was clear enough
My version has no if :)
parameters = raw_input()
sx, sy, sstartfrom, sjump, suntil = parameters.split()
x = "0123456789".index(sx)
y = "0123456789".index(sy)
startfrom = int(sstartfrom)
jump = int(sjump)
until = int(suntil)
for i in range(startfrom, until+jump, jump):
si = str(i)
booz = sx in si or i%x == 0
bang = sy in si or i%y == 0
print [[si, 'BANG'],['BOOZ','BOOZ-BANG']][booz][bang]
Easiest way to get the commas is to move the loop into a generator
def generator():
for i in range(startfrom, until+jump, jump):
si = str(i)
booz = sx in str(i) or i%x == 0
bang = sy in str(i) or i%y == 0
yield [[si, 'BANG'],['BOOZ','BOOZ-BANG']][booz][bang]
print ",".join(generator())
Sample output
$ echo 3 4 1 1 14 | python2 boozbang.py
1,2,BOOZ,BANG,5,BOOZ,7,BANG,BOOZ,10,11,BOOZ-BANG,BOOZ,BANG
$ echo 5 3 670 7 691 | python2 boozbang.py
BOOZ,677,BANG,691
$ echo 3 4 34 3 64 | python2 boozbang.py
BOOZ-BANG,BOOZ,BANG,BOOZ-BANG,BANG,BANG,BANG,55,58,61,BANG
def CheckCondition(number, xOrY):
return (xOrY in str(number)) or not (number % xOrY)
def SomeMethod(X, Y, start, jump, end):
for i in range(start, end, jump):
isPassX = CheckCondition(i, X)
isPassY = CheckCondition(i, Y)
if isPassX and isPassY:
print "BOOZ-BANG"
elif isPassX:
print "BOOZ"
elif isPassY:
print "BANG"
else:
print i
def YourMethod():
(X, Y, start, jump, end) = (3, 4, 1, 1, 14)
if (X not in range(1, 10) or Y not in range(1, 10)):
print "X and Y must be between 1 and 9"
if jump <= 0:
print "juump can't be less than 0"
SomeMethod(X, Y, start, jump, end)

Categories