DeeTee DeeTee - 1 month ago 12
Python Question

Python - stop a while loop in a method based on attribute change

I have a very simple class with one attribute and one method. i would like the method to run based on the value of the attribute. below is the class code:

class TestWhile()
def __init__(self):
self.status = "OFF"
def StreamV(self):
while self.Status == "ON"
print "nonstop"


basically what I want to do is set Status to ON, then run StreamV until Status is set to off. This is what i want as follows:

P = TestWhile()
T.Status = "ON"
T.StreamV()
T.Status = "OFF"


When I run the above test, it never makes it to the Status = "OFF" line and infinitely runs the loop. How can I fix this?

Answer

your call to T.StreamV() does what is commonly referred to as Busy looping and blocks the main thread. What you have effectively described you want is a background thread to update some value until a signal comes in (from your T.Status attribute)

Threading is relatively approachable for simple problems, and is an incredibly useful tool to get to know. From a super wide viewpoint a thread in python is a function that can run at the same time the main script is doing something else. In this regard python threads are indeed created by passing them a function to execute.

Example:

import threading
import time

class TestWhile(object):
    def __init__(self):
        self.status = "OFF"
        self.streamVthread = threading.Thread(target=self.StreamV) #create a thread for our streamV function
    def StreamV(self):
        print "starting thread"
        while self.Status == "ON":
            print "nonstop"
            time.sleep(1)
        print "stopping thread"

T = TestWhile() #our thread is actually created here, but is hasn't started yet
print 'T.Status -> "ON"'
T.Status = "ON"  #T.StreamV could be modified to run at creation and wait for this to change to "ON"
T.streamVthread.start() #this calls the T.StreamV function in a separate thread
time.sleep(6)
T.Status = "OFF"
print 'T.Status -> "OFF"'

I've added a bunch of print statements to help you understand the flow of the program. Please comment with any questions.

Edit: passing arguments to a thread

Threads exist in the same namespace as the main thread, so if they share a variable with the main script they will both have access to it. This can cause problems with multiple threads accessing the same thing at the same time (read more on locks and other mutex constructs). Passing arguments at creation of the thread however can be done as such:

import threading
import time

def sayHello(after_secs, name):
    time.sleep(after_secs)
    print("hello from {}".format(name))

thread1 = threading.Thread(target=sayHello, args=(3,"thread1"))
thread2 = threading.Thread(target=sayHello, args=(1,"thread2"))
thread3 = threading.Thread(target=sayHello, args=(5,"thread3"))

print "starting thread1"
thread1.start()
print "starting thread2"
thread2.start()
print "starting thread3"
thread3.start()


thread1.join() #wait for thread1 to finish
print "thread1 is done"
thread2.join() #wait for thread2 to finish
print "thread2 is done"
thread3.join() #wait for thread3 to finish
print "thread3 is done"

See if you can determine why these print statements happen in the order they do..