Why Python recursive function returns None [duplicate] - python

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 months ago.
The following code returns None on some values (eg 306, 136), on some values (42, 84), it returns the answer correctly. The print a and return a should yield the same result, but it does not:
def gcdIter (a,b):
c = min (a,b)
d = max (a,b)
a = c
b = d
if (b%a) == 0:
print a
return a
gcdIter (a,b%a)
print gcdIter (a,b)

You are ignoring the return value for the recursive call:
gcdIter (a,b%a)
Recursive calls are no different from calls to other functions; you'd still need to do something with the result of that call if that is what you tried to produce. You need to pass on that return value with return
return gcdIter (a,b%a)
Note that you can assign to multiple targets when assigning:
def gcdIter(a, b):
a, b = min(a, b), max(a, b)
if b % a == 0:
return a
return gcdIter(a, b % a)
You really don't need to care about the bigger and smaller values here. A more compact version would be:
def gcd_iter(a, b):
return gcd_iter(b, a % b) if b else abs(a)

Related

python question about iterative functions/ general functions

I have the following code, which i know to be wrong and also know what exactly is wrong, lack of 'return' before both iterative calls:
alpha = 546
beta = 66
def Euclid(a, b):
while not (a == 0 or b == 0):
if a >= b:
Euclid(a % b, b)
else:
Euclid(a, b % a)
return max(a, b)
print(Euclid(alpha, beta))
My question is why does the code above not still work? I viewed it in code visualiser, and it shows that the last value it returns is indeed max(a,b), so GCD, but then after the function keeps executing the code forever, going from arguments of (6,12) to (6,0), and then starting all over again with (6,12), after returning (6,0). Would just like to know what exactly is happening, since i thought function always quits after the last return.
Let's take a look at your Euclid function and try to understand what happens line by line (and also pay close attention to the values of the variables):
def Euclid(a, b):
while not (a == 0 or b == 0):
if a >= b:
Euclid(a % b, b)
else:
Euclid(a, b % a)
return max(a, b)
You call it with a = 546 and b = 66. (a=546 and b=66)
You enter the while loop because a!=0 and b!=0 (a=546 and b=66)
Since a>=b you call the Euclid function with a%b and b (a=546 and b=66)
You ignore the return value (a=546 and b=66) (actually this call never returns either, but let's assume for now it does)
You go back to the start of your while loop and start again (a=546 and b=66)
The problem is that you never modify the values of a and b, so your while condition will always be true, and your first call of the function never reaches the return.
Ps.: B Remmelzwaal is right about how to fix your code, I only explained what is happening, which makes you get stuck in an infinite loop. Based on his answer the correct code would be:
def Euclid(a, b):
while not (a == 0 or b == 0):
if a >= b:
return Euclid(a % b, b)
else:
return Euclid(a, b % a)
return max(a, b)
Ps2.: To clarify some misunderstanding, the while loop is un necessary in the code, since you would enter only once and return from it. The commands inside the while are never repeated.
The code which reflects better what is happening would be:
def Euclid(a, b):
if a!=0 and b!=0:
if a >= b:
return Euclid(a % b, b)
else:
return Euclid(a, b % a)
return max(a, b)
So in this case when you call the function with a = 546 and b = 66, the following is going to happen:
Euclid(546,66)
Euclid(18,66)
Euclid(18,12)
Euclid(6,12)
Euclid(6,0) --> This is not calling any more Euclids and returns 6
return 6
return 6
return 6
return 6
return 6
So the Euclid(6,0) gives you 6, the Euclid(6,12) returns the return value of Euclid(6,0), which was 6. And so on while you reach back to the Euclid(546,66).
You can imagine it as a matryoshka doll, every outer doll tells you the number which the inner doll told it. In this analogy the smallest inner doll is the Euclid(6,0) and every other doll just repeats it as it proceeds through the layers.

How is good the practis to compare arguments of function with it's names in Python?

I've made example functions, I know that i will use meta_function only with arguments sum and mult
def sum(a, b):
return a + b
def mult(a, b):
return a*b
def meta_function(function):
if function == sum:
c = 1
print('SUM')
elif function == mult:
c = 2
print("MULT")
print(c)
meta_function(sum)
meta_function(mult)
Output:
SUM
1
MULT
2
PyCharm informing me that Local variable might be referenced before assignment. I know, if some other arguments will be taken except sum and mult, this will lead to error. What is the best practice to handle this sophisticated issue? Try - except? Am I use wright way to take another functions in meta_function?
Pycharm warns you because if the function isn't sum or mult, your code will crash.
You need to define c at the top, just in case, or add an else statement.
# I changed the name of sum_ in order to avoid shadowing with
# the python built-in function sum()
def sum_(a, b):
return a + b
def mult(a, b):
return a * b
def meta_function(function):
c = 0 # if function isn't sum or mult, at least c exist
# here, "is" is better then "=="
if function is sum_:
c = 1
print('SUM')
# here, "is" is better then "=="
elif function is mult:
c = 2
print("MULT")
# Or you can do the else, but since you don't do anything in it,
# the best solution is to define a base state of c
# else:
# c = 0
print(c)
meta_function(sum_)
meta_function(mult)
Here is a better solution in my opinion, in order to prevent changing the core of meta_function() if you want to add more functions:
def sum_(a, b):
return a + b
def mult(a, b):
return a * b
function_switch = {
sum_: ('SUM', 1),
mult: ('MULT', 2),
}
def meta_function(function):
function_res = function_switch.get(function)
if function_res is None:
print(0)
return
print(function_res[0])
print(function_res[1])
meta_function(sum_)
meta_function(mult)
In Python 3.9, you can do:
def meta_function(function):
if (function_res := function_switch.get(function)) is None:
print(0)
return
print(function_res[0])
print(function_res[1])
Warning is shown because if both cases are not happened, then variable c will be not defined and print fill fail. The variable must be defined in the current scope.
It is better to make a generic function, executes the function and returns desired values. I've refactored your function as taking callable function and parameters for given function. Executes given callable and return some string that is built with return results.
def sum(a, b):
return a + b
def mult(a, b):
return a*b
def meta_function(func, *args):
# initialize default variables
c: int = None
return_str: str = None
# try execute given callable `func`
try:
# execute
c = func(*args)
# build some result string and assign
return_str = f"Function:{func.__name__}, Args: {args}, Result: {c}"
except Exception as exp:
# build result string for failed functions
return_str = f"Error calling given function `{func.__name__}` with params: {params}"
return return_str
def incompatible_func(x, y, z): # takes three parameters, will fail
return x + y * z
params = (1,2)
rslt = meta_function(sum, *params)
print(rslt)
rslt = meta_function(mult, *params)
print(rslt)
rslt = meta_function(incompatible_func, *params)
print(rslt)
And the output is:
Function:sum, Args: (1, 2), Result: 3
Function:mult, Args: (1, 2), Result: 2
Error calling given function `incompatible_func` with params: (1, 2)

python recursive immediate return [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 2 years ago.
I am very new python programming , while i write the below code inside the if statement the value of a is determined but , after i return to caller , return value is always none , Is there anything missing to return the value inside an if block on a recursive calls .
#! /usr/bin/env python3
def gcd_calc(a, b):
if(b == 0):
print(a)
return a
c= a%b
gcd_calc(b,c)
if __name__ == "__main__":
a, b = map(int, input().split())
if(a<b):
print(gcd_calc(a,b))
else:
print(gcd_calc(b,a))
You are missing a return
def gcd_calc(a, b):
if(b == 0):
print(a)
return a
c= a%b
return(gcd_calc(b,c)) #you need to return here as you are calling recursively
if __name__ == "__main__":
a, b = map(int, input().split())
if(a<b):
print(gcd_calc(a,b))
else:
print(gcd_calc(b,a))

Python BST code returning None instead of array? [duplicate]

This question already has answers here:
Why does my recursive function return None?
(4 answers)
Closed 7 months ago.
The following code returns None on some values (eg 306, 136), on some values (42, 84), it returns the answer correctly. The print a and return a should yield the same result, but it does not:
def gcdIter (a,b):
c = min (a,b)
d = max (a,b)
a = c
b = d
if (b%a) == 0:
print a
return a
gcdIter (a,b%a)
print gcdIter (a,b)
You are ignoring the return value for the recursive call:
gcdIter (a,b%a)
Recursive calls are no different from calls to other functions; you'd still need to do something with the result of that call if that is what you tried to produce. You need to pass on that return value with return
return gcdIter (a,b%a)
Note that you can assign to multiple targets when assigning:
def gcdIter(a, b):
a, b = min(a, b), max(a, b)
if b % a == 0:
return a
return gcdIter(a, b % a)
You really don't need to care about the bigger and smaller values here. A more compact version would be:
def gcd_iter(a, b):
return gcd_iter(b, a % b) if b else abs(a)

How do I use multiple variable from one function into another? [duplicate]

This question already has answers here:
Alternatives for returning multiple values from a Python function [closed]
(14 answers)
Closed 9 months ago.
When I try to call a, b in function add, I get a is not defined even though I am returning the values. How do I make it return both a and b?
def numbers():
a= input ("a:")
a = int(a)
b= input ("b:")
b = int(b)
return a
return b
def add():
numbers()
print (a)
print (b)
add()
A return statement almost always causes a function to immediately terminate, and no other statement in the function will run. So once you return a, you'll never get to return b. You need to return both of them at the same time.
Additionally, returning a value from a function will not automatically put those names into the scope that called the function. You need to manually assign the values to something.
def numbers():
a= input ("a:")
a = int(a)
b= input ("b:")
b = int(b)
return a,b
def add():
a,b = numbers()
print (a)
print (b)
add()
I think so:
def numbers():
a= input ("a:")
a = int(a)
b= input ("b:")
b = int(b)
return a, b
def add(a, b):
print (a)
print (b)
return a, b
def main():
another_a, another_b = numbers()
another_a, another_b = add(another_a, another_b)
main()

Categories

Resources