Why do I have to return function in the else case? Can't I just apply the defined function because I have to only return the value of b and store it?
def gcd_a(a,b):
if a==0:
return b
else:
gcd_a(b%a,a)
I think the main concept you are missing is that in order to get the result of a recursive function (or any function for that matter), the function that you access the result of must return the value*
Right now, when you call gcd_a, a recursive call to gcd_a will eventually return a value, however it will be lost, since the function that you are accessing the result of does not return a value.
To show you this is true, let's add in a log statement that prints when the function is returning:
def gcd_a(a,b):
if a==0:
print('finally returning!', b)
return b
else:
gcd_a(b%a,a)
Now if we call:
print(gcd_a(10, 99))
We get the following output:
finally returning! 1
None
Somewhere, a recursive call to gcd_a found your condition to be True, and returned 1, however, this result is not printed, because it is not returned by your call to gcd_a
* Unless you do something strange like updating a global variable, etc...
If your function finishes without returning anything, it will implicitly return None.
def double(val):
val * 2
value = double(10)
print(value)
Which is fine, except it doesn't have a return statement, and so all you get is None
The same applies to recursive functions: you can do all the recursive function calls you want, but if you don't actually return the result of the function, then it'll return None.
IMHO, the problem is in the way you are thinking about function which has to be cleared. The fact that you are having this doubt in a recursive function call is incidental because you are calling the same function again and again with different arguments causing different branches to be executed.
How will a function that doesn't return anything in any of its branches be helpful to its caller? In your case, what would happen if your function's caller calls it with an argument that hits your else block? It will return nothing and this won't help the caller!
Now in your recursive case, if your caller calls the function with an argument that hits the if block, then it would work as expected. However, if it hits the else block, then it would become a caller and call the same function again. For simplicity, let us assume that this time it hits the if condition and returns something to its caller. However, will that reach the original caller that initiated everything? The answer is no because you are not returning it to him!
Most of the times you would need a return for every branch in a function
unless you are doing it on purpose for a side effect.
In the else block, if you don't return the function call, the outer function returns None because python interpreter just runs whatever is returned by the gcd function.
Let's assume the following code:
def func():
10
In that function, it just runs 10, but it doesn't mean that there is some return from the function.
Related
i'm trying to update a default value in a combobox, after a function is called successfully, how could i do that?
my basic idea is this.
if xfunc return True : widget.set(updated_value)
return is a keyword that is used to return objects during runtime in a function, meaning if you write the word 'return' anywhere in the function (main or otherwise): the compiler will try to end the function with whatever follows as the return type. Therefore, when writing if statements: in your mind try to replace the function call 'xfunc()' with whatever you think it will return, and test to see if it is equal ('==') with the return you want ('True')
However, the job of a if-statement is to test if something is True. Therefore if xfunc() == True: would be redundant (as pointed out by all or None), so we can simplify this statement to if xfunc():
ex:
if xfunc():
#run success code here
So I have a python function that is explicitly returning a value, however my unittest receives None.
Here the function is seen returning a str value:
But my unittest receives None. see validation_result
Any ideas on what is causing the return value to default to None? I am explicitly returning a value??
The code you've highlighted just tells you what the value of the constant is - NOT that it's the value being returned from the method.
Your code returns before the return VALIDATION_SUCCESS statement is invoked - look for an empty return statement, or an explicit return None (or if VALIDATION_FAILED or other constants is set to None as well).
You can use the step through / step over functionality in your debugger to find out where it returns (since you've already set a breakpoint). Set the breakpoint at the start of the method / function you're calling into, and then step through the code to find out where your assumption is wrong.
I figured out my problem.
My execute function had a #decorator method that was missing a return statement, so the decorator had the returned value I was expecting, but then not returning the wrapped function containing it, and thus it was defaulting to None.
In the below simplified code, I would like to reuse a loop to do a preparation first and yield the result.
However, the preparation (bar()) function is never executed.
Is yield statement changing the flow of the function?
def bar(*args,**kwargs):
print("ENTER bar")
pass
def foo(prepare=False):
print("ENTER foo")
for x in range(1,10):
if prepare:
bar(x)
else:
yield x
foo(prepare=True)
r = foo(prepare=False)
for x in r:
pass
Because the foo definition contains a yield, it won't run like a normal function even if you call it like one (e.g. foo(prepare=True) ).
Running foo() with whatever arguments will return a generator object, suitable to be iterated through. The body of the definition won't be run until you try and iterate that generator object.
The new coroutine syntax puts a keyword at the start of the definition, so that the change in nature isn't hidden inside the body of the function.
The problem is that having a yield statement changes the function to returning a generator and alters the behavior of the function.
Basically this means that on the call of the .next function of the generator the function executes to the yield or termination of the function (in which case it raises StopIteration exception).
Consequently what you should have done is to ensure that you iterate over it even if the yield statement won't be reached. Like:
r = foo(prepare=True)
for x in r:
pass
In this case the loop will terminate immediately as no yield statement is being reached.
In my opinion, the actual explanation here is that:
Python evaluates if condition lazily!
And I'll explain:
When you call to
foo(prepare=True)
just like that, nothing happens, although you might expected that bar(x) will be executed 10 times. But what really happen is that 'no-one' demanding the return value of foo(prepare=True) call, so the if is not evaluated, but it might if you use the return value from foo.
In the second call to foo, iterating the return value r, python has to evaluate the return value,and it does, and I'll show that:
Case 1
r = foo(prepare=True)
for x in r:
pass
The output here is 'ENTER bar' 9 times. This means that bar is executed 9 times.
Case 2
r = foo(prepare=False)
for x in r:
pass
In this case no 'ENTER bar' is printed, as expected.
To sum everything up, I'll say that:
There are some cases where Python perform Lazy Evaluation, one of them is the if statement.
Not everything is evaluated lazily in Python,
for example:
# builds a big list and immediately discards it
sum([x*x for x in xrange(2000000)])
vs.
# only keeps one value at a time in memory
sum(x*x for x in xrange(2000000))
About lazy and eager evaluation in python, continue read here.
I'm viewing the source code of a project now. In which I saw a function like this.
def func(x):
if condition_a:
return
if condition_b:
return
process_something
What does this return with nothing do here?
The "return with nothing" exits the function at that line and returns None. As Python's docs say:
If an expression list is present, it is evaluated, else None is substituted.
return leaves the current function call with the expression list (or None) as return value.
In flow control, I've seen it commonly used when some sort of condition is encountered that makes it impossible to execute the rest of the function; for example,
def getDataFromServer():
if serverNotResponding():
return
# do important stuff here which requires the server to be running
I define a Factorial function named fab. I use generator to avoid stack overflow.But something I can't understand came up when I try to write a decorator version, which is more intuitive :
import types
def TCO(f):
def inner(*nkw,**kw):
gen=f(*nkw,**kw)
while isinstance(gen,types.GeneratorType):
gen=gen.next()
return gen
return inner
def fab(n,s=1):
if n<2:
yield s
else:
yield fab(n-1,s*n)
x=TCO(fab)
print x(2500) #this works fine, overcoming the limitation of tail-recursion.
fab=TCO(fab) #now just change the variable name.
print fab(5) #this woks fine.
print fab(2500) #this will raise an error :maximum recursion limit exceeded
Why? I know it has something to do with the same name fab, but why fab(5) works fine? I think when I define fab=TCO(fab), I actually change the object refered by f in inner to object TCO(fab). So when fab(5) runs, the gen will never be a generator! Because the inner never returns generator!
I am mad...Why ?
fab=TCO(fab)
statment now makes the variable fab points to the function inner. After that, when
yield fab(n-1,s*n)
is encountered, it is not actually calling the original fab function but the inner function which in turn calls the original fab function. Basically, you are coming out of the generator and entering another function every time. Thats why you are getting maximum recursion limit exceeded error.
I think this would be a good example to explain what happens:
def f(x):
print 'original'
if x > 0:
return f(x-1)
return 0
g = f
def f(x):
print 'new'
return x
print g(5)
result:
original
new
4
this proves:
1.when g(5) runs, origninal `f` is called, not new `f`.
2.as 5>0, 'return f(x-1)' is executed
3.new `f` is called when `f(x-1)` runs. so the result is 4.
Your original version yields a generator which yields a generator which yields a generator, etc. To evaluate that linked list you then use the while loop in you TCO decorator. It all is based on the fact that you are linking generators to avoid a large stack.
This concept is broken when you assign something new to the variable fab. Then yielding fab(n-1, s*n) in fab is accessing the new fab variable and thus not returning a generator anymore but a value. To compute that value, the stack is used, hence you can get the stack overflow problem.