Trying to understand recursive functions and so created this program but the output is incorrect. Would like to understand what am I doing wrong here
class Recursive:
def __init__(self, arr):
self.arr = arr
self.sum = 0
def sumRecursive(self):
if len(self.arr) == 0:
return self.sum
self.sum = self.arr.pop(0)
return self.sum + self.sumRecursive()
def main():
recur = Recursive([1,2,3])
print(recur.sumRecursive())
main()
output: 9
There are two types of recursion to consider: tail recursion, where the return value of a single recursive call is returned as-is, and "regular" recursion, where you do something with the return value(s) of the recursive call(s) before returning yourself.
You are combining the two. You either add a value from the list to the recursive sum, using no accumulator:
def non_tail_recursive(self):
if len(self.arr) == 0:
return 0
return self.arr.pop(0) + self.non_tail_recursive()
or you use an accumulator:
def tail_recursive(self):
if len(self.arr) == 0:
return self.sum
self.sum += self.arr.pop(0)
return self.tail_recursive()
You don't usually use an object with state to implement recursion. If you're keeping state, then you often don't need a recursive solution at all.
Here's how to do a "stateless" recursive sum.
def sumRecursive(arr):
if not arr:
return 0
return arr[0] + sumRecursive(arr[1:])
def main():
print(sumRecursive([1,2,3]))
main()
Your self.sum attribute is redundant. The information being processed by a recursive algorithm rarely needs members to pass information along.
class Recursive:
def __init__(self, arr):
self.arr = arr
def sumRecursive(self):
if not len(self.arr):
return 0
return self.arr.pop(0) + self.sumRecursive()
def main():
recur = Recursive([1,2,3])
print(recur.sumRecursive())
main()
Output: 6
To answer your question without rewriting your code (since obviously there are better ways to sum arrays), the answer is that the last leg of your recursion calls self.sum + self.sumRecursive which hits your sumRecursive function one last time which returns (from your if statement) self.sum which is the last element in your list (which you already summed).
Instead when the array is empty, return 0.
class Recursive:
def __init__(self, arr):
self.arr = arr
self.sum = 0
def sumRecursive(self):
if len(self.arr) == 0:
return 0
self.sum = self.arr.pop(0)
return self.sum + self.sumRecursive()
def main():
recur = Recursive([1,2,3,4])
print(recur.sumRecursive())
main()
Optionally move your if to the bottom where I personally think it makes more sense:
def sumRecursive(self):
self.sum = self.arr.pop(0)
if len(self.arr) == 0:
return self.sum
else:
return self.sum + self.sumRecursive()
fundamentals
You are making this more challenging for yourself because you are tangling your sum function with the class. The sum function simply needs to work on a list but the context of your object, self, is making it hard for you to focus.
Recursion is a functional heritage and this means writing your code in a functional and modular way. It's easier to read/write small, single-purpose functions and it promotes reuse within other areas of your program. Next time you need to sum a list in another class, do you want to rewrite sumRecursive again?
Write your summing function once and then import it where it's needed -
# mymath.py
def mysum(t):
if not t:
return 0
else:
return t.pop() + mysum(t)
See how mysum has no concern for context, self? Why should it? All it does it sum the elements of a list.
Now write your recursive module -
# recursive.py
from mymath import mysum
class Recursive:
def __init__(self, arr): self.arr = arr
def sum(self): return mysum(self.arr)
See how Recursive.sum just hands off self.arr to mysum? It doesn't have to be more complicated than that. mysum will work on every list, not just lists within your Recursive module. We don't have to know how mysum works, that is the concern of the mymath module.
Now we write the main module. Each module represents a barrier of abstraction. This means that the details of a module shouldn't spill over into other modules. We don't know how Recursive actually sums the input, and from the caller's point of view, we don't care. That is the concern of Recursive module.
# main.py
from recursive import Recursive
recur = Recursive([1,2,3])
print(recur.sum())
6
going functional
Above we wrote mysum using the .pop technique in your question. I did this because that seems to be how you are understanding the problem right now. But watch what happens when we do this -
x = [1,2,3]
print(mysum(x)) # 6
print(mysum(x)) # 0
Why does the mysum return a different answer the second time? Because as it is written now, mysum uses t.pop(), which mutates t. When mysum is finished running, t is completely emptied!
By why would we write our function like this? What if 5 + x returned a different result each time we called it?
x = 3
print(5 + x) # 8
print(5 + x) # 8
How annoying it would be if we could not depend on values not to change. The sum of the input, [1,2,3], is 6. But as it is written, the sum of the input is to return 6 and empty the input. This second part of emptying (changing) the input is known as a side effect. Ie, the desired effect is to sum and emptying of the input list is unintended but a consequence of us using .pop to calculate the result. This is not the functional way. Functional style means avoiding mutations, variable reassignments, and other side effects.
def mysum(t):
if not t:
return 0
else:
return t[0] + mysum(t[1:])
When written in this way, t, is not changed. This allows us to use equational reasoning whereby we can substitute any function call for its return value and always get the correct answer
x = [1,2,3]
mysum(x)
== 1 + mysum([2,3])
== 1 + 2 + mysum([3])
== 1 + 2 + 3 + mysum([])
== 1 + 2 + 3 + 0
== 1 + 2 + 3
== 1 + 5
== 6
And x was not changed as a result of running mysum -
print(x)
# [1,2,3]
Note, the Recursive module does not need to make any change to receive the benefit of rewriting mysum in this way. Before the change, we would've seen this behavior -
# main.py
from recursive import Recursive
recur = Recursive([1,2,3])
print(recur.sum())
print(recur.sum())
6
0
Because the first call to sum passes self.arr to mysum which empties self.arr as a side effect. A second call to recur.sum() will sum an empty self.arr! After fixing mysum we get the intended behaviour -
# main.py
from recursive import Recursive
recur = Recursive([1,2,3])
print(recur.sum())
print(recur.sum())
6
6
additional reading
I've written extensively about the techniques used in this answer. Follow the links to see them used in other contexts with additional explanation provided -
I want to reverse the stack but i dont know how to use recursion for reversing this… How can i reverse the stack without using Recursion
Finding all maze solutions with Python
Return middle node of linked list with recursion
How do i recursively find a size of subtree based on any given node? (BST)
Deleting node in BST Python
I have to execute the following code wherein I will be calling the function main again and again.
so here as I need to use i = i+1, I need to declare and initialize i in the first place right, but when i call the main function it again defines i=0 and the whole purpose of i = i+1 is lost.
How can I solve this error?
I have given the condition just as an example.
Basically what I want is i should be initialized only once, inspite of how many number of times main is called.
def main():
i = 0
if 0<1:
i = i+1
y = i
There are a couple ways to do this that don't involve globals. One is capture the value of i in a closure and return a new function that increments this. You will need to call the initial function once to get the returned function:
def main():
i = 0
def inner():
nonlocal i
i += 1
return i
return inner
f = main()
f()
# 1
f()
# 2
You can also create a generator which is a more pythonic way to do this. The generator can be iterated over (although use caution since it iterates forever) or you can get a single value by passing it to next():
def main():
i = 1
while True:
yield i
i += 1
f = main()
next(f)
# 1
next(f)
# 2
You can also use itertools.count
So you haven't declared i as a global variable
Do something like this
global i
i = 0
def main():
if 0<1:
global i
i = i+1
y = i
The reason behind this is because inside a function all the variables are local meaning they only exist inside the function while the function is called, so if you want a function to be able to change a variable for the whole code, you'll need to announce it as a global so python knows to change the value of it for the entire code
I'm not sure exactly what you are trying to do, but I believe there is an easier way to do whatever it is you are doing
It looks like you want to maintain state in a function call which is a good reason to convert it to a class.
class MyClass:
def __init__(self):
self.i = 0
def main(self):
self.i += 1
y = self.i
myclass = MyClass()
myclass.main()
myclass.main()
print(myclass.i)
I'd like to take an example code for this:
def coun(n):
count = 0
def counter():
nonlocal count
if count < n:
count += 1
return count
return counter
cntrl = coun(4)
print(cntrl())
why must we assign the function to an identifier, further more in the print statement, the cntrl is invoked using parenthesis, and in the return statement of the function coun the counter is not returned using parenthesis. What is this?(I'm just a novice at python)
Assigning functions to identifiers isn't neccesary to invoke them.
Consider simple example:
def function_factory():
def f(x):
return x
return f
You may assign function returned from factory to identifier and use it as any other named function:
my_f = function_factory()
assert my_f(1) == 1
Or you can drop intermediate assignment and do it in one line:
assert function_factory()(1) == 1
It's not
Because you are doing return counter rather than return counter() you are returning a function rather than the result of that function, in order to get the result you need to call this function. You can do this, as you have done, by assigning it to a variable or you can call it immediately with the usual function call convention:
print(coun(4)())
I need one global variable s = set() to help me with certain recursive function. After I ran the function, I want it to be an empty set again. Is there any simple way for me to do it? I'm using python 3.4.1
ADD: So I want to traverse a tree to get the number of distinct nodes. In order to do that I use a global variable SET = set() to keep records of the same nodes. After I called the function, I want to reset the global variable SET.
SET = set()
def distinct_node_count(root):
global SET
if not root.children:
if root.value.__repr__() not in SET:
SET.add(root.value.__repr__())
return 1
else:
return 0
else:
if root.value.__repr__() not in SET:
SET.add(root.value.__repr__())
return 1 + sum([distinct_node_count(child) for child in root.children])
else:
return sum([distinct_node_count(child) for child in root.children])
don't use a global variable but a paramater with a default value
something like this
def recursive(oneparam, secondparam,*, s=None):
if s is None:
s = set()
if secondparam < 0:
return 0
return 1 + recursive(oneparam,secondparam-1,s=s)
The previous version don't change really the contract but if you absolutly don't want to be able to add an additional parameter just use an auxiliary function
def recursive(oneparam, secondparam):
def inner(oneparam, secondparam, s):
if secondparam < 0:
return 0
return 1 + inner(oneparam,secondparam-1,s)
inner(oneparam,secondparam,set())
I want to create an iterator that counts the length of another iterator while consuming it.
Here is a working example of what I want to achieve:
from random import random
def randleniter(p):
while random() < p:
yield 7
count = 0
def do():
def countiter(piter):
global count
for i in piter:
count += 1
yield i
list(countiter(randiter(0.99))) #simulator for a different method consuming the iterator
return count
>>> do()
81
However, I would have never built it like this if I intended to use a global variable. I imagined that since I can do this with nested methods:
def make_adder(x):
def add(y):
return x + y
return add
I would be able to do this:
def do():
count = 0
def countiter(piter):
for i in piter:
count += 1
yield i
list(countiter(randiter(0.99)))
return count
but this results in a UnboundLocalError: local variable 'count' referenced before assignment. When I print locals() from inside the countiter - it doesn't include count.
Can I make countiter access count somehow?
what you are describing is known as a closure, which is a topic completely independant from iterators and generators.
Python3.x has the nonlocal keyword for that (just declare nonlocal count in countiter to match your desired behaviour, in python 2.7, you have to emulate this via mutable objects (since inner function can read and mutate outer functions variables, just not assign to them).
so you can in fact do:
def do():
count = [0,]
def countiter(iter):
for i in iter:
count[0] += 1
yield i
list(countiter(randiter(0.99)))
return count[0]