python question about iterative functions/ general functions - python

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.

Related

Using a function as an argument in another function through decorators

Here is the code:
def smart_divide(func):
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
else:
return func(a,b)
return inner
#smart_divide
def divide(c,d):
return c/d
divide(5,2)
This is a program to divide two numbers and give an error message if the denominator is 0.
We are passing 5 and 2 as an argument to the function divide. How does inner function know that the value of a and b is 5 and 2 respectively?
According to what I read on internet : #smart_divide means that divide = smart_divide(divide(c,d))
The function divide has parameters c,d while the function inner has parameters a,b. How does the interpreter know that a = c and b = d?
#smart_divide means that
result = smart_divide(divide)(c,d)
That means, divide no points to inner function, and inner function calls the original function divide via func.
divide = smart_divide(divide(c,d)) is not really a good description of what happens. Have a look at the logical expansion step by step, in some kind of pseudo-Python:
divide(x, y)
= smart_divide(lambda c, d: c / d)(x, y)
= inner[func ~> lambda c, d: c / d](x, y)
= (def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
else:
return (lambda c, d: c / d)(a, b))(x, y)
= print("I am going to divide",a,"and",b)
if y == 0:
print("Whoops! cannot divide")
else:
return (lambda c, d: c / d)(x, y))
= print("I am going to divide",a,"and",b)
if y == 0:
print("Whoops! cannot divide")
else:
return x / y
The important thing that happens is lexical scoping. If you substitute an expression in another expression (the ~> operation above), then you assume that the names don't get mangled. That is, (lambda a: lambda b: a)(b)) does not become lambda b: b, but (something equivalent to) lambda b_prime: b. Names don't matter: this is called alpha equivalence.
Your understanding of decorators is almost right, this should clarify things.
The code in your example:
#smart_divide
def divide(c,d):
return c/d
Is functionally identical to:
def simple_div(c,d):
return c/d
divide = smart_divide(simple_div)
divide is defined as the inner of the smart_divide decorator.
smart_divide is given simple_div as a parameter (func), which is what inner uses to call the originally decorated simple_div method.
Furthermore: smart_divide can be used to decorate multiple functions because a new inner function is created each time smart_divide is called, so the func reference is different each time.

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)

Why Python recursive function returns None [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)

Can't understand codes for "def gcd()"

Update: Once I don't know 3 %4 =0 ...
def gcd(a, b):
"""Calculate the Greatest Common Divisor of a and b.
Unless b==0, the result will have the same sign as b (so that when
b is divided by it, the result comes out positive).
"""
while b:
a, b = b, a%b
return a
I think it works like this:
gcd(3,4) => while 4: => 3,4 = 4, 3%4 =>
Let's walk through this step-by-step.
def gcd(a, b):
This defines a new function gcd which uses the variables a and b in its calculations. These values must be set before the function begins.
while b:
Unless a number is equivalent to 0, it is thought of as true. So, if b = 0, then this part of the code will not execute.
a, b = b, a%b
For clarity, I am going to expand this to two lines.
a = b
b = a%b
The first part is rather self explanatory - the second is decidedly not. a%b is a python expression for a (mod b) Modulo's are mathematical functions which, at their most basic state, return the remainder of two numbers. For instance, 12%5 = 2; the remainder of 12/5is 2.
When writing the actual code though, make sure to keep them on the same line. "In one line the assignments happen at the same time (courtesy of tuple packing and unpacking). In two lines the assignments happen one after the other, which gives an incorrect answer (b will always be 0)" - Tim
Those lines repeat indefinitely until the variable b is equivalent to 0. After that, the code executes this:
return a
That returns the value a to the rest of the program, so that it can be used later on. It also ends the function.
To read more about Euclid's Equation (And... since I love cryptography and math, the 'Extended' edition) go to this Wikipedia page.
I hope that this was helpful!
Here is a recursive version of the gcd function.
def gcd(a, b):
c = a%b
if c == 0:
return b
return gcd(b, c)

Python Koan 131 raising exceptions

I am learning Python by doing Python Koans these days, and I came up with the problem of raising exceptions in Python. Specifically, I am even confused with try...except... after going through the koan. I know there is a similar question toward Rudy Koan Ruby Koan 151 raising exceptions. But I am a Python newbie and know nothing about Ruby.
So here is the koan:
# You need to finish implementing triangle() in the file 'triangle.py'
from triangle import *
class AboutTriangleProject2(Koan):
# The first assignment did not talk about how to handle errors.
# Let's handle that part now.
def test_illegal_triangles_throw_exceptions(self):
# Calls triangle(0, 0, 0)
self.assertRaises(TriangleError, triangle, 0, 0, 0)
self.assertRaises(TriangleError, triangle, 3, 4, -5)
self.assertRaises(TriangleError, triangle, 1, 1, 3)
self.assertRaises(TriangleError, triangle, 2, 4, 2)
the following is triangle.py
def triangle(a, b, c):
# DELETE 'PASS' AND WRITE THIS CODE
if a == b and b == c and c == a:
return 'equilateral'
if a == b or b == c or a == c:
return 'isosceles'
else:
return 'scalene'
# Error class used in part 2. No need to change this code.
class TriangleError(StandardError):
pass
I am supposed to finish triangle() function.
To my understanding, the try...except... functions like if certain criteria satisfied then do something, else through out an exception. Then in my situation, should I use if ... then raise TriangleError or try... except ...? What are the differences between them?
Thank you very much!
Please see the following answer:
def triangle(a, b, c):
# DELETE 'PASS' AND WRITE THIS CODE
if min([a,b,c])<=0:
raise TriangleError
x,y,z = sorted([a,b,c])
if x+y<=z:
raise TriangleError
if a==b and b==c and c==a:
return 'equilateral'
if a==b or b==c or a==c:
return 'isosceles'
else:
return 'scalene'
You want to use raise, which will cause an exception to be created and travel up the call stack until something handles the exception with a try/except block. For example, if you were using this triangle function in real code you would do something like
try:
t = triangle(x, y, z)
...
except TriangleError:
print 'Triangle', x, y, z, 'is no good!'
That way you'd be able to handle the error when a bad triangle was made and your program wouldn't crash.
here is my code,it worked
def triangle(a, b, c):
# DELETE 'PASS' AND WRITE THIS CODE
if min([a,b,c])<=0:
raise TriangleError,"no <0 numbers"
if sorted([a,b,c])[0]+sorted([a,b,c])[1]<=sorted([a,b,c])[2]:
raise TriangleError,"sf"
set_a=set(([a,b,c]))
if len(set_a)==1:
return 'equilateral'
elif len(set_a)==2:
return 'isosceles'
elif len(set_a)==3:
return 'scalene'
# Error class used in part 2. No need to change this code.
class TriangleError(StandardError):
pass
I ended up with something similar to nancy's answer, using set rather than comparing a,b and c manually, and it worked also.
def triangle(a, b, c):
# DELETE 'PASS' AND WRITE THIS CODE
ls = sorted([a,b,c])
if min(ls)<=0 or ls[0]+ls[1]<=ls[2]: raise TriangleError, 'Triángulo mal formado.'
l = len(list(set(ls)))
if(l==1): return 'equilateral'
if(l==2): return 'isosceles'
if(l==3): return 'scalene'
# Error class used in part 2. No need to change this code.
class TriangleError(StandardError):
pass
The better solution for the triangle.py file has been given below:
def triangle(a, b, c):
if a <= 0 or b <= 0 or c <= 0:
raise TriangleError(AttributeError('Negative edge is not allowed'))
if a + b + c <= 2 * max(a, b, c):
raise TriangleError(AttributeError('largest side should be smaller than sum of 2 other sides'))
if a == b == c:
return 'equilateral'
elif a == b or b == c or c == a:
return 'isosceles'
return 'scalene'
Error class used in part 2. No need to change this code.
class TriangleError(Exception):
pass

Categories

Resources