Beginner trying to debug an easy program - python

I'm a student and am just beginning to learn code. Right now I'm working with Python and have a program I think should work, but just returns some errors that I don't understand:
Traceback (most recent call last): File "C:\Program
Files\Notepad++\1913lab3.py", line 23, in print(most(odd,
[]))
File "C:\Program Files\Notepad++\1913lab3.py", line 9, in most N =
S[i] UnboundLocalError: local variable 'i' referenced before
assignment
I don't understand what the first error tells me, but the I think I understand the second one, but I don't understand why I'm getting it. I don't think i is a local variable as I defined it right away in the beginning. Here's the code:
t = 0
f = 0
i = 0
def odd(N):
return N % 2 != 0
def most(P, S):
N = S[i]
if P == True:
t += 1
else:
f += 1
i += 1
if i < len(S):
most(P, S)
else:
if t > f:
return 'True'
else:
return 'False'
print(most(odd, []))
print(most(odd, [0]))
print(most(odd, [1]))
print(most(odd, [1, 2]))
print(most(odd, [1, 2, 3]))
The assignment is to define a recursive function (most()). The function takes one function and one list as its arguments (P and S). I can't use loops or local variables. Here's a quote from the assignment:
"P is a function of one argument that returns either True or False,
and S is a list. The function most calls P on each element of S. It
must return True if P returns True more often than it returns False.
It must return False otherwise."
The 5 print commands are just 5 examples that I need to work for credit, but this program needs to work for all lists. If anyone can help me fix these errors, that'd be great. (Also, any general Python tips would be welcome.)

By default any variable that is modified within a function is assumed to be local to that function. So if you have i += 1, i must be defined within the function first. Or you have to declare i as a global first (global i) so that python knows it is refering to the i you have defined (first) outside the function. But beware with globals, they are often dangerous (as they make it hard to keep track what is going on) and should be avoided if possible.

Related

Understanding the code behind a gridtraveller

I found a basic code in python to find the numbers of paths you can take in a (m,n) grid if you can only go either down or right.
def gridtraveller(m,n):
if m == 0 or n == 0:
return 0
elif m == 1 or n == 1:
return 1
return gridtraveller(m-1,n) + gridtraveller(m,n-1)
But I dont understand why is this working for two thing:
What does def something (m,n) do ?
And why does here we return the definition ? ( I do understand why we return
m-1 and n-1 , but I don't understant the concepte of a def returning a def)
Thanks to you and sorry english is not my first language.
In Python the def keyword is simply used to define a function, in this case it's the function gridtraveller(m,n). What you're seeing with that last return statement is actually a function returning the value of another function. In this case it's returning the value of another call to gridtraveller, but with different parameter values; this is called recursion. An important part of recursion is having appropriate base cases, or return values that won't end in another recursive call(i.e. the return 0 or return 1 you see).
It can be easier to understand by simply stepping through a few iterations of the recursive calls. If your first function call starts with m = 2 and n = 1, the first call will end with return gridtraveller(1,1) + gridtraveller(2,0). The first call in that statement will then return 1 since either m or n are 1 and the second returns 0 since n = 0 here giving a total result of 1. If larger values of m and n are used it will obviously result in a higher number since more calls to gridtraver(m,n) will happen.

What's the different between calling function with and without 'return' in recursion?

I tried to create recursive function for generating Pascal's triangle as below.
numRows = 5
ans=[[1],[1,1]]
def pascal(arr,pre,idx):
if idx==numRows:
return ans
if len(arr)!=idx:
for i in range (0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
if len(arr)==idx:
arr+=[1]
ans.append(arr)
pascal([1],arr,idx+1)
a = pascal([1],ans[1],2)
return a
The output I got was an empty list [ ]. But if I add return when calling pascal as
return pascal([1],arr,idx+1)
the output was correct [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]].
As I understand, a should have been assigned by return ans. Then why a failed to get an answer when calling pascal without return and why return is necessary in this case?
When you have recursion, you usually combine the returns in some way. Could be a sum, like fibonacci:
fibonacci(n+1) = fibonnaci(n)+fibonacci(n-1)
Or appending a line to a matrix, like your case. Anyway, if you don't have a return, you have no information to combine! Consider the fibonnaci case without return:
def fibonnaci(n):
if n<2:
return 1
fib_ans = fibonnaci(n-2)+fibonnaci(n-1)
In this case, if I called fibonnaci(0) or fibonnaci(1) the output would be 1, like you return ans if idx == numRows, but if I called fibonnaci(2), then the variable fib_ans would receive 2, which is the expected answer, but it would be available outside the scope of the funtion. Python "would add" return None to the end of my function, just below the fib_ans attribution. So, I need to return fib_ans
Well as far as i know, if you want to get a value back you need the "return" statement...
The point is if you don't have "return", you will be getting no values back...
Hopefully this helps..
For all algol languages that has a return keyword it exits the nearest function completely and the result of it is the result of the expression of the return argument. eg.
def test(v):
if v == 0:
return someFun(10)
...
If v is zero the result of the function is the value returned by someFun(10). The rest of the function denoted by ... is never executed unless v is nonzero.
If we write the same without return:
def test(v):
if v == 0:
someFun(10)
...
Now, when v is zero someFun(10) is still called, but the value returned by it is discarded and in order for it to have any true meaning someFun needs to do some side effects, like printing, storing values, updating object. In addition all the rest of the function denoted by ... is then continued once someFun(10) is done.
For Python and many other languages not having a return at all doesn't mean it doesn't return anything. In Python there is an invisible return None in the last line of every function/method.
When you do pascal([1],arr,idx+1), you are doing the recursive call but then discarding the value which it returns. If you want to return it to the caller, then you need to use explicitly return pascal(...).
In fact recursion is not necessary in this example anyway. You could easily refactor your code to use a simple for loop. For example:
def pascal(numRows):
ans = [[1]]
for _ in range(1, numRows):
pre = ans[-1]
arr = [1]
for i in range(0,len(pre)-1,1):
arr+=[pre[i]+pre[i+1]]
arr+=[1]
ans.append(arr)
return ans
print(pascal(5))
(I'm using the name _ here as the for loop variable according to convention because it is a dummy variable not used inside the loop, but you could use something else e.g. row if you prefer.)
The above is as close to the original code as possible, but you should also consider using arr.append(value) in place of arr += [value] -- this would be the normal way to append a single value to a list.

Function in Python is treating list like a global variable. How to fix this?

I'm not sure why l would be modified by the find() function. I thought since I'm using a different variable in another function, l would not be modified by the function since it's not global.
I made sure it wasn't an error in the code by copy and pasting l = [2, 4, 6, 8, 10] before every print statement, and it returned the right outputs, meaning l is being changed by the function. I also removed the main function from the main and basically made it outright global, but it still gave the original bad results.
I'm not sure if this is an issue with my understanding of Python since I'm a beginner in it and I'm coming from Java.
Here's the code and results:
def find(list, user):
while True:
n = len(list)
half = int(n/2)
if n == 1:
if user != list[0]:
return "Bad"
else:
return "Good"
elif user == list[half]:
return "Good"
elif user > list[half]:
del list[0:half]
elif user < list[half]:
del list[half:n]
print(list)
if __name__ == "__main__":
l = [2, 4, 6, 8, 10]
print(find(l, 5)) # should print Bad
print(find(l, 10)) # should print Good
print(find(l, -1)) # should print Bad
print(find(l, 2)) # should print Good
but it returns with this
[2, 4]
[4]
Bad
Bad
Bad
Bad
You should read this question at first. why can a function modified some arguments while not others.
Let me rewrite your code for clarification.
def find(li, el):
# li is a list, el is an integer
# do something using li and el
if __name__ == "__main__":
l = [1,2,3,4]
e = 2
find(l, e)
The function find received two objects as parameters, one is li and the other is el. In main, we defined two objects, a list, we called it l, and an integer, we called it e. Then these two objects was passed to find. It should be clear that it is these two objects that passed to the function, not the name. Then your find function has access to this object, called l in main, while called li in find. So when you change li in find, l changed as well.
Hope that answers your question. And to fix this, check deepcopy.
Arguments in Python are passed by assignment. https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference
In your case, that means that the list parameter of your find function is assigned the exact same list you pass in as the argument l. So, when you modify list (which is a very bad name since it shadows Python's list keyword), you also modify l, since no copy of the original was made.
You could use copy() to pass in a copy, but I think you would do well to reconsider the function as a whole, since it currently has many, many issues and you're likely to end up with a solution that won't suffer from having the original list passed in.

Error in below python code

I am new to python program. the below code has some error with list.
len = []
def collatz_length(n,count):
++count
if len[n]:
return len[n]
if n == 1:
len[n] = count
elif n & 1:
len[n] = count + collatz_length(3 * n + 1,0)
else:
len[n] = count + collatz_length(n >> 1,0)
return len[n]
print collatz_length(13,0)
i am trying to figure out the length.But the gives error
OUTPUT
Traceback (most recent call last):
File "collatz.py", line 21, in <module>
print collatz_length(13,0)
File "collatz.py", line 9, in collatz_length
if len[n]:
IndexError: list index out of range
It means that n is beyond the length of the list (which is initially zero). Rather than doing len[n], you want to see if n is in your list:
# Renaming your array to my_array so that it doesn't shadow the len() function,
# It's also better to put it as a parameter, not a global
def collatz_length(n, count, my_array):
if n < len(my_array):
return my_array[n]
# ... all your elses
If you have an array with 5 things in it, and try to access array[5], you are reading outside the bounds of the array. I think that is what is happening, but your code is also very hard to understand. If that's not what is happening, you may need to add some comments or otherwise clarify what you are doing. It looks like you have an empty array and are trying to access location 13 in it, which makes no sense.

Convert tuple to concatenating the digits by recursion

def untuplify(tpl):
if len(tpl) == 0:
return 0
n = 0
while n <= len(tpl) - 1 :
x += str(tpl[n])
n += 1
return x
Why am I getting this error UnboundLocalError: local variable 'x' referenced before assignment ??
untuplify((1, 2, 3, 4, 5))
Should give me 12345
You are getting that error because in the line x+=str(tpl[n]) your compiler don't know x
First, there is no recursion here, you never call untuplify from within itself.
Second, the error message is because of the line
x += str(tpl[n])
You've never used x before, and now you want to add to it. That doesn't work.
Place a
x = ''
before the loop?
There are vastly easier ways to do this, but I think you're doing this as an exercise and aren't interested in them.
Edit: also, are you sure it makes sense to return the number 0 if the tuple is empty? Isn't the function supposed to return a string?
Because you are not initializing x:
n, x = 0, ''

Categories

Resources