I am learning Python 3 and working on an exercise that calls for writing a Python program which simulates/reads a BASIC program as input. I am stuck on writing the part of the Python program that should detect infinite loops. Here is the code I have so far:
def execute(prog):
while True:
location = 0
if prog[location] == len(prog) - 1:
break
return "success"
getT = prog[location].split()
T = len(getT) - 1
location = findLine(prog, T)
visited = [False] * len(prog)
Here, prog is a list of strings containing the BASIC program (strings are in the form of 5 GOTO 30, 10 GOTO 20, etc.).
T is the target string indicated in prog[location].
If the BASIC program has an infinite loop, then my Python program will have an infinite loop. I know that if any line is visited twice, then it loops forever, and my program should return "infinite loop".
A hint given by the tutorial assistant says "initialize a list visited = [False] * len(prog) and change visited[i] to True when prog[i] is visited. Each time through the loop, one value updates in visited[]. Think about how you change a single value in a list. Then think about how you identify which value in visited[] needs to change."
So this is the part I am stuck on. How do I keep track of which strings in prog have been visited/looped through?
I'm not sure I agree that visiting a line twice proves an infinite loop. See the comments under the question. But I can answer the actual question.
Here's the hint:
A hint given by the tutorial assistant says "initialize a list visited = [False] * len(prog) and change visited[i] to True when prog[i] is visited. Each time through the loop, one value updates in visited[]. Think about how you change a single value in a list. Then think about how you identify which value in visited[] needs to change."
This is saying you should have two lists, one that contains the program, and one that contains true/false flags. The second one is to be named visited and initially contains False values.
The Python code is just like the hint says:
visited = [False] * len(prog)
This uses the * list operator, "list repetition", to repeat a length-1 list and make a new list of a longer length.
To change visited[i] to True is simple:
visited[i] = True
Then you can do something like this:
if visited[i]:
print("We have already visited line {}".format(i))
print("Infinite loop? Exiting.")
sys.exit(1)
Note that we are testing for the True value by simply saying if visited[i]:
We could also write if visited[i] == True: but the shorter form is sufficient and is customary in the Python community. This and other customary idioms are documented here: http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
For a program this small, it's not too bad to keep two lists like this. For larger and complex programs, I prefer to keep everything together in one place. This would use a "class" which you might not have learned yet. Something like this:
class ProgramCode(object):
def __init__(self, statement):
self.code = statement
self.visited = False
prog = []
with open(input_basic_program_file, "rt") as f:
for line in f:
prog.append(ProgramCode(line))
Now instead of two lists, we have a single list where each item is a bit of BASIC code and a visited flag.
P.S. The above shows an explicit for loop that repeatedly uses .append() to add to a list. An experienced Python developer would likely use a "list comprehension" instead, but I wanted to make this as easy to follow as possible.
Here's the list comprehension. Don't worry if it looks weird now; your class will teach this to you eventually.
with open(input_basic_program_file, "rt") as f:
prog = [ProgramCode(line) for line in f]
I know of no automatic way of infinite loop detection in Python, but by using divide and conquer methods and testing individual functions, you can find the offending function or block of code and then proceed to debug further.
If the Python program outputs data, but you never see that output, that's a good indicator you have an infinite loop. You can test all your functions in the repl, and the function that does "not come back" [to the command prompt] is a likely suspect.
You can write output under a debug variable of some sort, to be shut off when everything works. This could be a member variable of a Python class to which your code would have to have access to at any time, or you could have a module-scoped variable like Debug=1 and use debug levels to print varying amounts of debug info, like 1 a little, 2 more, 3, even more, and 4 verbose.
As an example, if you printed the value of a loop counter in a suspected function, then eventually that loop counter would keep printing well beyond the count of data (test records) you were using to test.
Here is a combination I came up with using parts of J. Carlos P.'s answer with the hints that steveha gave and using the hint that the instructions gave:
def execute(prog):
location = 0
visited = [False] * len(prog)
while True:
if location==len(prog)-1:
return "success"
findT = prog[location].split()
T = findT[- 1]
if visited[location]:
return "infinite loop"
visited[location] = True
location = findLine(prog, T)
Related
So here's my code.
def bubblesort(list):
global step
global oldlist
print("""
ORIGINAL LIST""")
print(list)
for i in range(len(list)):
for j in range(len(list)-1):
if float(list[j])>float(list[j+1]):
list[j], list[j+1] = list[j+1], list[j]
if oldlist==list:
**end(list)**
else:
oldlist=list
step=step+1
print("""
STEP""",step)
print(list)
end(list)
def end(list):
global step
step=step+1
print("""
STEP""",step)
print(list)
step=0
oldlist=[]
list=[]
number=int(input("How many numbers do you want to input to sort? : "))
for i in range(1,number+1):
value=float(input("INPUT NUMBER : "))
list.append(value)
bubblesort(list)
The issue is the bit of code which I have is "end(list)" bare in mind I've included the ** to make it easier to see on here it's not actually in the code. It simply won't call the subroutine when I ask it to. I know it definitely runs through the if since if i put a "print" or "break" in they both work it just won't jump to a sub-routine. Furthermore, the time I call that subroutine later on in the code works and does go to the subroutine. So i'm a bit lost as to what I've done wrong here. Any help? Would be much appreciated :)
There are quite a few things wrong with your code, and your question. Let's go through them:
First of all, the formatting was not great (I've suggested an edit). This might not sound like a big deal ("Hey, as long as it works...") but it's actually crucial: I work with python every day, and I had trouble understanding your code
You're talking about subroutines. In python, we usually refer to those as functions, or methods.
You're using globals variables all over the place. This might work in little toy examples like this one, but it will fall apart VERY fast
As David Buck said, list is one of the basic data structures: 1 in an instance of int and [1,2,3] is an instance of list). It's a really bad idea to override it.
I'm not sure what you're trying to do with the end() function. It seems do very little, and what it does is not related to its name...
You create an oldlist list but never really do anything with it. What is it supposed to to ?
With that in mind, here is my proposition:
def main():
# I like to put the main code in a "main" function, so that it can be at the top
# of the file. We'll call main() from the bottom of the file
# Make our program pretty, with a little branding
print("===== Number Sorter 9000 =====")
# 'numbers' is not the name of anything yet, so we can use it safely
numbers = []
# This will loop forever, unless we tell it to stop. It allows us to skip the
# part where you ask the user for a number of values: Simply enter the values
# one by one, and press enter once last time when done.
while True:
value = input(f"Number {len(numbers)+1} (leave empty to continue): ")
# Decide what to do with the value we received. If it's a number,
# add it to our list, if it's empty, stop collecting numbers
if value:
# Make sure the value is a number ()
value = float(value)
# Add the number to the list
numbers.append(value)
else:
# This will get us out of the number-asking loop
break
print("Number Sorter 9000 will now sort your numbers")
sorted_numbers = bubblesort(numbers)
print("Number Sorter 9000 has sorted your numbers:")
print(sorted_numbers)
def bubblesort(numbers):
# Here I've removed things that were not doing much.
# There are some ways to improve the algorithm itself, but I'll let you do that
for i in range(len(numbers)):
for j in range(0, len(numbers)-i-1):
if numbers[j] > numbers[j+1]:
numbers[j], numbers[j+1] = numbers[j+1], numbers[j]
# We 'return' the result from the function, so that code that calls the
# bubblesort() function can use the result
return numbers
# Lastly, we call the "main" function to get everything started. Without this
# line, nothing happens: We've just explained to the computer how to do some
# stuff, but we haven't asked it to *DO* anything
main()
Well, I hope this was not too much information. I've tried to keep things simple, but feel free to ask if something is not clear
def function():
while True:
...omission...(this function is repeated permanently)
i =0
while i < 4:
driver.execute_script("""window.open("URL")""")
driver.switch_to.window(driver.window_handles[-1])
time.sleep(1)
function()
time.sleep(1)
i += 1 #open new tab and run function.
it doesn't work because while true loop is repeated permanently. Is there any ways to run multiple functions together?
https://imgur.com/a/4SIVekS This picture shows what I want
According to your picture, what you want is to launch the function a set number of times (4?), and run those in parrallel.
On a single core, as is the normal behavior, straight up parallel processing is impossible. You need to access other cores and manage a decentralized processing. while is useless there. I'm worried the level of difficulty is over your current skills, but here we go.
The overall flow that you (probably, depends on the actual memory safety of your functions) need is:
- to create a thread pool with the set number of threads for the number of runs you want.
- indicate the function you need to run
- start them, making sure the start itself is non-blocking.
- ensure one functions's processing doesn't impact another's results. race conditions are a common problem.
- gather results, again, in a non-blocking way.
You can use several methods. I highly recommend you read up a lot on the following documentations.
Threading:
https://docs.python.org/3/library/threading.html
Multiprocessing:
https://docs.python.org/3/library/multiprocessing.html
I don't understand your question because I don't understand what your function is supposed to do.
while True:
will always create an infinite loop. "while" is a command that tells python to loop through the following block so long as the expression following it evaluates to True. True always evaluates to True.
It seems like you want to use a conditional, like you do in "while x < 4".
x < 4
...is an expression that evaluates to true when x is less than 4, and false if x is not less than 4. Everything below the line:
while x < 4:
will then run if x is less than 4, and when it's done running that code, it will go back and evaluate if x is less than 4 again, and if it is, run the code again. To include another while loop inside of that loop, that new loop also needs an expression to evaluate. If you want to evaluate the same expression, write it out:
while x < 4:
# do something
while x < 4:
#do more things
# do even more things
# change x at some point, or else you're in an infinite loop.
However, there's no reason to do that specifically, because you're already doing it. All of the code is only running when x < 4, so checking that condition again right there is redundant, and doing it in another loop doesn't make sense. If the inside loop is also incrementing x, then the outside loop won't loop and doesn't need to increment x.
Also, if you want a function to check a condition based on a variable outside the function, you'll want to pass things to that function.
When solving a question of Project Euler I ran into the following logical error related to when n is updated.
while(n<1000):
#update n
#do something with n
#do stuff
vs
while(n<1000):
#do something with n
#do stuff
#update n
In the first instance, I ended up performing an operation with n even though the condition of n<1000 is violated.
Does this logical error have a name? How common is this bug?
I tried to look for it, I did find things about pre-incrementing and post-incrementing a variable. Although that is close to the error, it isn't exactly what is happening here. I found a reference to this in a SO answer about for loop vs while loop in the part describing how for loops are more concise and direct when compared to while loops. Essentially with while loops we end up running code after a variable update which could be buried somewhere in the code.
This is not always a bug: it depends on the algorithm. In some cases, you know that the original value of n is legal (so you can enter the loop), but you want to update and use the new value in your processing. You need to match your code to your algorithm. Your second code block is the canonical for-equivalent, and is more common.
This falls under the general heading of "off by 1 error".
This code was written in Python 3. I am trying to find the 10001st prime number.
#10001st prime number
mylist=[]
def prime_index(n):
for i in range(99**99):
for x in range(2, int(i**1/2)):
if i % x == 0:
return False
return True
mylist.append(i)
n=int(n+1)
print(mylist[n])
break
prime_index(10001)
When I run, it says "list index out of range", referring to print(mylist[n]).
However I have been adding primes to the list along the way in the mylist.append(i). So can someone tell me what is the problem here because I do not understand what is going on. Is 99**99 too small? Or more subtle problem with code?
99**99 is not too small; if you actually print it, you're well beyond what you need (if you tried to run it out, you'd never finish, it's 657 bits of work). But your loop makes no sense; your inner loop will return either True or False immediately if it executes even once.
"Luckily" for you, it never executes even once. The first outer loop sets i to 0 the first time, so the inner loop doesn't run at all (side-note, you probably want i ** (1/2), not i ** 1 / 2; exponentiation has higher precedence than division). Because it doesn't run, you end up indexing into an empty list (and asking for index 10001 no less).
There are far too many problems in this code to address them all; look for other trial division prime finding code to get an idea of what it should look like.
The problem is that you try to print out the 10001st element as soon as you find (or not) the first prime. Also, note that you return from the routine without finding any prime number -- if you were to get that far. There is no way to reach the append statement.
You got to the print statement only because your first iteration has i = 0, so you don't enter the for loop at all.
Please follow the posting guidelines: take the time to research how to generate prime numbers. It can be much faster than you're doing, and will give you a nice, succinct bit of code to put into your program.
I'm pretty new to this whole "programming thing" but at age 34 I thought that I'd like to learn the basics.
I unfortunately don't know any python programmers. I'm learning programming due to personal interest (and more and more for the fun of it) but my "social habitat" is not "where the programmers roam" ;) .
I'm almost finished with Zed Shaws "Learn Python the Hard Way" and for the first time I can't figure out a solution to a problem. The last two days I didn't even stumble upon useful hints where to look when I repeatedly rephrased (and searched for) my question.
So stackoverflow seems to be the right place.
Btw.: I lack also the correct vocabular quite often so please don't hesitate to correct me :) . This may be one reason why I can't find an answer.
I use Python 2.7 and nosetests.
How far I solved the problem (I think) in the steps I solved it:
Function 1:
def inp_1():
s = raw_input(">>> ")
return s
All tests import the following to be able to do the things below:
from nose.tools import *
import sys
from StringIO import StringIO
from mock import *
import __builtin__
# and of course the module with the functions
Here is the test for inp_1:
import __builtin__
from mock import *
def test_inp_1():
__builtin__.raw_input = Mock(return_value="foo")
assert_equal(inp_1(), 'foo')
This function/test is ok.
Quite similar is the following function 2:
def inp_2():
s = raw_input(">>> ")
if s == '1':
return s
else:
print "wrong"
Test:
def test_inp_2():
__builtin__.raw_input = Mock(return_value="1")
assert_equal(inp_1(), '1')
__builtin__.raw_input = Mock(return_value="foo")
out = StringIO()
sys.stdout = out
inp_1()
output = out.getvalue().strip()
assert_equal(output, 'wrong')
This function/test is also ok.
Please don't assume that I really know what is happening "behind the scenes" when I use all the stuff above. I have some layman-explanations how this is all functioning and why I get the results I want but I also have the feeling that these explanations may not be entirely true. It wouldn't be the first time that how I think sth. works turns out to be different after I've learned more. Especially everything with "__" confuses me and I'm scared to use it since I don't really understand what's going on. Anyway, now I "just" want to add a while-loop to ask for input until it is correct:
def inp_3():
while True:
s = raw_input(">>> ")
if s == '1':
return s
else:
print "wrong"
The test for inp_3 I thought would be the same as for inp_2 . At least I am not getting error messages. But the output is the following:
$ nosetests
......
# <- Here I press ENTER to provoke a reaction
# Nothing is happening though.
^C # <- Keyboard interrupt (is this the correct word for it?)
----------------------------------------------------------------------
Ran 7 tests in 5.464s
OK
$
The other 7 tests are sth. else (and ok).
The test for inp_3 would be test nr. 8.
The time is just the times passed until I press CTRL-C.
I don't understand why I don't get error- or "test failed"-meassages but just an "ok".
So beside the fact that you may be able to point out bad syntax and other things that can be improved (I really would appreciate it, if you would do this), my question is:
How can I test and abort while-loops with nosetest?
So, the problem here is when you call inp_3 in test for second time, while mocking raw_input with Mock(return_value="foo"). Your inp_3 function runs infinite loop (while True) , and you're not interrupting it in any way except for if s == '1' condition. So with Mock(return_value="foo") that condition is never satisfied, and you loop keeps running until you interrupt it with outer means (Ctrl + C in your example). If it's intentional behavior, then How to limit execution time of a function call in Python will help you to limit execution time of inp_3 in test. However, in cases of input like in your example, developers often implement a limit to how many input attempts user have. You can do it with using variable to count attempts and when it reaches max, loop should be stopped.
def inp_3():
max_attempts = 5
attempts = 0
while True:
s = raw_input(">>> ")
attempts += 1 # this is equal to "attempts = attempts + 1"
if s == '1':
return s
else:
print "wrong"
if attempts == max_attempts:
print "Max attempts used, stopping."
break # this is used to stop loop execution
# and go to next instruction after loop block
print "Stopped."
Also, to learn python I can recommend book "Learning Python" by Mark Lutz. It greatly explains basics of python.
UPDATE:
I couldn't find a way to mock python's True (or a builtin.True) (and yea, that sounds a bit crazy), looks like python didn't (and won't) allow me to do this. However, to achieve exactly what you desire, to run infinite loop once, you can use a little hack.
Define a function to return True
def true_func():
return True
, use it in while loop
while true_func():
and then mock it in test with such logic:
def true_once():
yield True
yield False
class MockTrueFunc(object):
def __init__(self):
self.gen = true_once()
def __call__(self):
return self.gen.next()
Then in test:
true_func = MockTrueFunc()
With this your loop will run only once. However, this construction uses a few advanced python tricks, like generators, "__" methods etc. So use it carefully.
But anyway, generally infinite loops considered to be bad design solutions. Better to not getting used to it :).
It's always important to remind me that infinite loops are bad. So thank you for that and even more so for the short example how to make it better. I will do that whenever possible.
However, in the actual program the infinite loop is how I'd like to do it this time. The code here is just the simplified problem.
I very much appreciate your idea with the modified "true function". I never would have thought about that and thus I learned a new "method" how tackle programming problems :) .
It is still not the way I would like to do it this time, but this was the so important clue I needed to solve my problem with existing methods. I never would have thought about returning a different value the 2nd time I call the same method. It's so simple and brilliant it's astonishing me :).
The mock-module has some features that allows a different value to be returned each time the mocked method is called - side effect .
side_effect can also be set to […] an iterable.
[when] your mock is going to be
called several times, and you want each call to return a different
value. When you set side_effect to an iterable every call to the mock
returns the next value from the iterable:
The while-loop HAS an "exit" (is this the correct term for it?). It just needs the '1' as input. I will use this to exit the loop.
def test_inp_3():
# Test if input is correct
__builtin__.raw_input = Mock(return_value="1")
assert_equal(inp_1(), '1')
# Test if output is correct if input is correct two times.
# The third time the input is corrct to exit the loop.
__builtin__.raw_input = Mock(side_effect=['foo', 'bar', '1'])
out = StringIO()
sys.stdout = out
inp_3()
output = out.getvalue().strip()
# Make sure to compare as many times as the loop
# is "used".
assert_equal(output, 'wrong\nwrong')
Now the test runs and returns "ok" or an error e.g. if the first input already exits the loop.
Thank you very much again for the help. That made my day :)