string theorist string theorist - 4 months ago 9
Python Question

Referencing a variable from a different thread/class in python?

What I'm trying to achieve is quite simple.

So basically, I have a thread that loops continuously, grabbing data from the same url and updating a variable called "data", with text each time. The variable is stored locally within the class.

Then I have a second class which is the mainframe. It should display the latest data, which is determined by whatever the variable in the first class is set to.

The problem is that I cannot find a way to reference that variable from the other class/thread.

The name of the variable that I am setting, and trying to reference is "data".

Here is the source code:

#!/Library/Frameworks/Python.framework/Versions/3.5/bin/python3
# -*- coding: utf-8 -*-

from tkinter import *
import time
import urllib.request
from bs4 import BeautifulSoup
import threading
from queue import Queue

class httpReq(threading.Thread):

def run(self):

i = 0
while 1<5:
url = "https://twitter.com/realDonaldTrump"
page = urllib.request.urlopen(url)
soup = BeautifulSoup(page, "html.parser")
self.data = data = soup.title.text
print(x)

x = httpReq()
x.start()

class Example(Frame, httpReq):

def __init__(self, parent):
Frame.__init__(self, parent)

self.parent = parent
self.initUI()

def initUI(self):

self.parent.title("IT Support App")
self.pack(fill=BOTH, expand=True)

frame1 = Frame(self)
frame1.pack(fill=X)

lbl1 = Label(frame1, text="Primary Video Stream", width= 20)
lbl1.pack(side=LEFT, padx=5, pady=5)


lbl6 = Label(frame1, text= x.data)
lbl6.pack(fill=X, padx=5, expand=True)

frame2 = Frame(self)
frame2.pack(fill=BOTH, expand=True)

lbl2 = Label(frame2, text="Primary Audio Stream", width=20)
lbl2.pack(side=LEFT, padx=5, pady=5)

entry2 = Entry(frame2)
entry2.pack(fill=X, padx=5, expand=True)

frame3 = Frame(self)
frame3.pack(fill=BOTH, expand=True)

lbl3 = Label(frame3, text="Backup Video Stream", width=20)
lbl3.pack(side=LEFT, padx=5, pady=5)

entry3 = Entry(frame3)
entry3.pack(fill=X, pady=5, padx=5, expand=True)

frame4 = Frame(self)
frame4.pack(fill=BOTH, expand=True)

lbl4 = Label(frame4, text="Backup Audio Stream", width=20)
lbl4.pack(side=LEFT, padx=5, pady=5)

entry4 = Entry(frame4)
entry4.pack(fill=X, pady=5, padx=5, expand=True)

frame5 = Frame(self)
frame5.pack(fill=X)

lbl5 = Label(frame5, text="IPTV", width=20)
lbl5.pack(side=LEFT, padx=5, pady=5)

entry5 = Entry(frame5)
entry5.pack(fill=X, pady=5, padx=5, expand=True)

def main():

root = Tk()
root.geometry("1920x1080")
app = Example(root)
root.mainloop()


if __name__ == '__main__':
main()

Answer

It turns out that there are various ways of doing this. For my purposes however, (since only one thread writes to the variable, and the others read-only) I have found that using a global variable does the job.

First declare and set the variable to none, outside the thread. Then within each thread, declare the variable as global:

#!/Library/Frameworks/Python.framework/Versions/3.5/bin/python3
# -*- coding: utf-8 -*-

from tkinter import *
import time
import urllib.request
from bs4 import BeautifulSoup
import threading
from queue import Queue

data = None

class httpReq(threading.Thread):
    def run(self):

        global data

        while True:
            url = "https://twitter.com/realDonaldTrump"
            page = urllib.request.urlopen(url)
            soup = BeautifulSoup(page, "html.parser")
            data = soup.title.text
            print(data)

x = httpReq()
x.start()

class Example(Frame):

        global data

        def __init__(self, parent):
            Frame.__init__(self, parent)
            self.parent = parent
            self.initUI()

        def initUI(self):
            self.parent.title("Example App")
            self.pack(fill=BOTH, expand=True)

            frame1 = Frame(self)
            frame1.pack(fill=X)

            lbl1 = Label(frame1, text="Title Data:", width= 20)
            lbl1.pack(side=LEFT, padx=5, pady=5)

            lbl2 = Label(frame1, text= data)
            lbl2.pack(fill=X, padx=5, expand=True)

def main():
    root = Tk()
    root.geometry("600x200")
    app = Example(root)
    root.mainloop()

if __name__ == '__main__':
    main()
Comments