I'm trying to identify a few errors in this code below and write which kind of error it is and replace it with the correct code. I've found the three but I have a question on differentiating whether one is a runtime or a logic error.
def mirror(word): # 1
result == '' # 2
ord_a = ord('a') # 3
ord_z = ord('z') # 4
for c in word[:-1]: # 5
value = ord('c') - ord_a # 6
new_value = ord_z - value # 7
result += chr(new_value) # 8
return result # 9
I've successfully identified 4 lines (line 2, line 5, line 6, line 9) and made adjustments (testing various inputs work in the new function) here:
def mirror(word): # 1
result = '' # 2 ##### runtime error* or logic?
ord_a = ord('a') # 3
ord_z = ord('z') # 4
for c in word[::-1]: # 5 ##### logic error (supposed to reverse slicing)
value = ord(c) - ord_a # 6 ##### logic error (ord(c) not ord('c'))
new_value = ord_z - value # 7
result += chr(new_value) # 8
return result # 9 ###### syntax error (wrong indent)
My question is would line 2 count as a runtime error or a logic error, given that in the erroneous code it was comparing equality "==" rather than referencing an assignment with "=" .
Cheers
The errors can be best delineated as follows:
A syntax error is something caught by the compiler/interpreter and it's incorrect use of the language itself. For example, for:, which is invalid Python.
A runtime error is a problem that cannot be detected before the code runs but causes an issue that is caught during the program run. An example would be x = open("nosuchfile.txt") because the file is checked for existence only at runtime.
A logic error is something that isn't caught, either at compile or runtime but which causes an issue. An example would be working out the sum of all numbers from one to n inclusive with the_sum = sum([x for x in range(n)] - that wouldn't include the n in the sum.
If you actually call the function with something like:
print("running")
mirror("hello")
you will see there are no syntax errors because it successfully starts running.
Using the definitions above:
result == '' is a runtime error, it detects that you are trying to compare the uninitialised result with something (a result = 7 before that makes the error go away).
Everything else is a logic error since it neither prevents compilation nor stops it running because of an unrecoverable fault.
Related
I'm just starting out in learning recursion and after reading some articles I am wondering why it looks like recursion ignores operand errors. For example, I know you can't add an integer to a list and I know the following cannot execute:
>>> 1 + [2,3]
That will and should produce an unsupported operand type error.
However, when the following code is passed [1,2,3] it executes without fail:
def list_sum_recursive(input_list):
# Base case
if input_list == []:
return 0
# Recursive case
else:
head = input_list[0]
smaller_list = input_list[1:]
return head + list_sum_recursive(smaller_list)
The output is 6, which is correct for the sum of the elements in the list, but when I try to map out the stacks all I see is a stack of int + list which in my mind I know should throw an error. What am I not getting about how lists work in recursion? Can anyone explain to me why this code executes without throwing an error?
The line you're confused about must be return head + list_sum_recursive(smaller_list). You're right, this would be problematic if head is an int and the other object returned by the recursive call is a list - however, ask yourself, at what point does your function ever return a list? Your function can either return 0 (the base case), or it can return head + some int.
list_sum_recursive doesn't return a list; it returns the sum of the values in its argument:
list_sum_recursive([]) == 0
list_sum_rescursive([1]) == 1 + list_sum_recursive([])
== 1 + 0
== 1
list_sum_rescursive([1, 2]) == 1 + list_sum_recursive([2])
== 1 + (2 + list_sum_recursive([]))
== 1 + (2 + 0)
== 1 + 2
== 3
If you were to provide type hints for this function, it might look something like
def list_sum_recursive(input_list: List[int]) -> int
Not just any list can be passed, as it is assumed that input_list[0] will be something you can add to (ultimately) 0.
For context, this code is written on a video within the channel Numberphile by Matt Parker talking about multiplication persistence. The code is written in Python 2, and my question is about the line return "DONE".
Evidently, this prevents an infinite loop from being generated, as it is clear running an example (below) with and without that line:
def per(n, steps = 0):
if len(str(n)) == 1:
print "TOTAL STEPS " + str(steps)
return "DONE"
steps += 1
digits = [int(i) for i in str(n)]
result = 1
for j in digits:
result *= j
print result
per (result, steps)
per(27)
# 14
# 4
# TOTAL STEPS 2
Now, the same code without the line return "DONE" would not end the loop, and yield:
14
4
TOTAL STEPS 2
4
TOTAL STEPS 3
4
TOTAL STEPS 4
4
TOTAL STEPS 5
4
TOTAL STEPS 6
4
TOTAL STEPS 7
4
TOTAL STEPS 8
4
TOTAL STEPS 9
4
TOTAL STEPS 10
4
TOTAL STEPS 11
4
TOTAL STEPS 12
4
TOTAL STEPS 13
4
TOTAL STEPS 14
4
...
My question is about the meaning of 'return "HOME"'. Does it simply mean STOP. Is there any meaning of "HOME" in there?
If you were to run the function in a variable assignment you would literally get "DONE". I'm assuming you mean "DONE" instead of "HOME" since there is no return "HOME" in your example.
For instance:
x = per(7)
print(x)
Would print the usual output and also print DONE when you called print(x). Because 7 is a single digit the condition if len(str(n)) == 1 is met on the first run..
TOTAL STEPS 0
DONE
This function calls itself though, which makes it a confusing choice to learn about this stuff since that's fairly unusual. If we run the script with a number with more than one digit, we'll get None instead.. because it never runs the return statement, it's return value is the python default, which is a NoneType:
x = per(27)
print(x)
Result:
14
4
TOTAL STEPS 2
None
Because 27 doesn't meet the condition of having a single digit.. the script calls itself with the results it's printing out.. until it finally uses 4.. which meets the condition and prints out the TOTAL STEPS line.
To see this value we have to modify the function:
def per(n, steps = 0):
if len(str(n)) == 1:
print("TOTAL STEPS " + str(steps))
return "DONE"
steps += 1
digits = [int(i) for i in str(n)]
result = 1
for j in digits:
result *= j
print(result)
x = per(result, steps)
print("Inner return", x)
x = per(27)
print("Outer return", x)
Result:
14
4
TOTAL STEPS 2
Inner return DONE
Inner return None
Outer return None
Thankfully you don't have to worry too much about return values.. since you aren't capturing the return value in a variable in your example.. just using return by itself would have the same result. Which is to stop running the function at that point, and to move on to the line after per(27) if there was one.. it can be a useful way to see what's happening in this function though.
Using variable assignment with = is not the only way to use a return value.. just the easiest way to demonstrate what's happening.
for instance just running print(per(27)) would have the same result as my example.
The return inside the if statement is just a termination for your recursive function - have you noticed that you are calling per(x) inside itself?
If we take out the return, the function will not terminate, and Python will raise a max recursive exception.
Now your function does this: if length of n is 1, terminate; otherwise, call another per function until somewhere it meets your termination condition.
But your per is not actually returning anything when len(str(n)) != 1. By default, a function implicitly returns None. So even though per(1) returns "Done", the returned value will not be propagated to the function which calls it.
To make it clearer, what you might need is (which guarantees the return value will be consistent with different input):
def per(n, steps=0):
if len(str(n)) == 1:
return "Done"
# some other code
return per(result, steps)
And another definition is also consistent:
def per(n, steps=0):
if len(str(n)) == 1:
return # None
# some other code
per(result, steps)
# implicitly return None
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.
This question already has answers here:
Understanding recursion in Python
(4 answers)
Closed 3 years ago.
Found this solution to make a factorial() function in python, but I am having trouble with understanding 'why' it works.
The function is :
def factorial(x):
if x <= 1:
return 1
else:
return x * factorial(x-1)
I'm having trouble understanding where the actual multiplication happens?
It would seem to me, that the function would keep calling itself until it gets to 1, and returns 1. Can someone enlighten me? I'm sure I'm missing something easy.
Consider a few easy examples:
calling factorial(1)
this will immediately return 1
calling factorial(2)
x is 2 in our first scope.
we will enter the else block
we mulitply x, which is 2 with factorial(x-1).
*x-1 is 1.
We call factorial(1) which is our first case. The result is 1.
we return 2
This is basically it, for any higher number we get more scopes, always calling factorial with one less, eventually reaching 1 where we terminate and start returning back values.
Where the multiplication happens:
# +-------------------------- HERE .MUL A, B happens
# | | |
# | v v
# | x ( !(x-1) )
# v
return x * factorial(x-1)
# ---------( -1)
# | | <--------------- vvvvvvvvv
# THIS sends recursive call
# to get B-value "down the line"
# while A is waiting to
# to receive B value
# needed for .MUL A, B
# B waits for return value
# from "recusive" call
# to the same function,
# but with off by one
# smaller number
# UNTIL A == 2 | more exactly A { 2 | 1 | 0 }
# B == 1 | B { 1 | 0 | -1 }
# for which case | for which case
# factorial( 1 ) RETs 1 | factorial( B ) RETs 1
# as a terminal state
# without any .MUL
# without any deeper
# level
# recursion
# call
# thus
# "terminal"
# state
# and since this moment, all "waiting" .MUL A, B-s start to get processed
# from back to front
# one step after another
# 1 * 2 * 3 * .. * A
# which is the definition of !A
# Q.E.D.
This is why it works
A general tip for programming is to insert print statements to help you see what's happening as the code runs. This is especially useful when you have broken code that you are trying to fix but is also good for understanding new code. In this case try running the following:
def factorial(x):
print "x", x
if x <= 1:
print "base case, returning 1"
return 1
else:
sub_fact = factorial(x-1)
print "factorial(x-1)", sub_fact
result = x * sub_fact
print "return", result
return result
factorial(4)
Let's say you call factorial(3), here's how it would look.
factorial(3):
return 3 * factorial(2) = ?
can't return yet since it doesn't have a value, call factorial(2)
factorial(2):
return 2 * factorial(1) = ?
can't return yet since it doesn't have a value, call factorial(1)
factorial(1):
return 1
now bubbling up, since factorial(1) returns 1
factorial(2) = 2 * 1
returns 2
factorial(3) = 3 * 2
returns 6
end of operation
Basically stack frame gets created for every call to the factorial(x) and hierarchy of stack frame is formed.Every call waits for the answer from the next call and so on.Finally, when answer is received by the main call it returns the answer.
A stack frame is a part of the call stack, and a new stack frame is created every time a subroutine is called. So, in our recursive Factorial method above, a new stack frame is created every time the method is called. The stack frame is used to store all of the variables for one invocation of a routine. So, remember that a call stack is basically a stack of stack frames.
Yes, factorial of 0 and 1 is 1 and there is no multiplication nor next recursive call.
Else, you have to note that before we multiply with current x, we must get the result out of next factorial.
So, the recursion "enters" itself down to the stop condition (when x==1) and then result rises back, like this:
factorial(5):
(5 *(4 *(3 *(2 *(1*1)))))
- Read it from right to left, which is the order of recursive execution
- Note: (1*1) would not actually be executed because at x==1 recursion stops.
Because of multiplication rule (a*b = b*a) the direction is irrelevant (top to bottom or bottom to top).
I'm very new to Python and am trying to teach myself a few things using various online resources. In the WIkipedia article on algorithms, there is a sample BASIC program; I've decided to try and write the same program using Python, but I am running into problems with the syntax of my if/else statements. I'm pretty sure it's a basic formatting problem, but I don't have enough experience with coding to understand what I'm doing wrong. The following chunk of code:
# Euclid's algorithm for greatest common divisor
print "Euclid's algorithm for greatest common divisor"
print "Type two integers greater than 0"
("\n")
("\a")
# Gather input from user in the form of a string.
("\n")
a = raw_input("Integer 1? ")
("\n")
b = raw_input("Integer 2? ")
("\n")
# Calculate equalities.
if b = 0:
print a
elif a > b:
a = a - b
print a
b = b - a
if b = 0:
print a
returns the error:
File "euclid.py", line 35
if b = 0:
^
SyntaxError: invalid syntax
I realize the module as a whole is incomplete, but I would like to try to figure out what I'm doing wrong in this part before I move on to the next part.
Two issues:
if b = 0: # this is assignment; you want == which is comparison
print a
elif a > b:
a = a - b # this needs to be indented just like the print under the if clause
You are using assignment where you wanted to test for equality. Use two = signs:
if b == 0:
b = 0 is an assignment statement, and you cannot use statements inside of other statements; b == 0 tests if b is equal to 0.
= is assignment (as in x=4, which means set x=4). == is equality checking. You want ==.
python requires indentation.
Thus
if True:
print 'happy'`
is a syntax error, whereas
if True:
print 'happy'
is okay.
This isn't strictly speaking a syntax error, but what are the ("\n") statements in your code there for? Currently they don't do anything.
For most programming languages checks for equality are denoted by a double equal sign meaning check if these are equal and return true/1 or false/0. This is because you need to distinguish between asking if two things are equal and stating the relation.
So use == instead of =