Python Forum
send function output from one py file to another (OOP)
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
send function output from one py file to another (OOP)
#1
Basically im trying to send an optionemenu selected item from one py file to another while using OOP. The problem is the class first gets initialized and after some time the optionmenu output gets sent. I'm trying to send the function output to the "Data" file from the "UI" file. i take the result of the optionmenu selection to a dictionary in the "Data" file which in turn uses the slected key value (a URL) to download and format the dictionary file. The problem is that the class gets initialized first so by the time the selection is sent the data variable remains None and cannot be changed. Please help. Beginner btw as im guessing is obvious
Reply
#2
Post some code please.

This makes no sense:
Quote:The problem is that the class gets initialized first so by the time the selection is sent the data variable remains None and cannot be changed.
Variables don't freeze at initialization. You can assign a different value to a variable at any time. I don't think this is your problem. So what is your problem?

Is the problem that the variable is not assigned in a timely manner? Maybe you have some code in Data that needs to know option menu selection before it is called. If so, you have two options. The first is delay making an instance of the Data class until you select something from the option menu. The second, and better solution in my opinion, is write the Data class such that the code affected by the option menu selection can be called at any time. Which solution is a better fit for you, really depends on what you are doing. That is why you really need to post some code.
Reply
#3
(Aug-16-2023, 04:35 AM)deanhystad Wrote: Post some code please.

This makes no sense:
Quote:The problem is that the class gets initialized first so by the time the selection is sent the data variable remains None and cannot be changed.
Variables don't freeze at initialization. You can assign a different value to a variable at any time. I don't think this is your problem. So what is your problem?

Is the problem that the variable is not assigned in a timely manner? Maybe you have some code in Data that needs to know option menu selection before it is called. If so, you have two options. The first is delay making an instance of the Data class until you select something from the option menu. The second, and better solution in my opinion, is write the Data class such that the code affected by the option menu selection can be called at any time. Which solution is a better fit for you, really depends on what you are doing. That is why you really need to post some code.
that is the problem. How would i go about delaying to make an instance of the Data class untill the option menu output is selected?
Reply
#4
Quote:that is the problem. How would i go about delaying to make an instance of the Data class untill the option menu output is selected?
When you make a control, you can bind it to a function. Activate the control, and the function gets called. You already reference that here:
Quote:and after some time the optionmenu output gets sent
If you need to delay creating an object until the "optionmenu output gets sent", create the object inside the function that is executed when "the optionmenu output gets sent".

If you post your code I can give you a more specific answer.
lunacy90 likes this post
Reply
#5
(Aug-20-2023, 07:13 PM)deanhystad Wrote:
Quote:that is the problem. How would i go about delaying to make an instance of the Data class untill the option menu output is selected?
When you make a control, you can bind it to a function. Activate the control, and the function gets called. You already reference that here:
Quote:and after some time the optionmenu output gets sent
If you need to delay creating an object until the "optionmenu output gets sent", create the object inside the function that is executed when "the optionmenu output gets sent".

If you post your code I can give you a more specific answer.
code from Data class (the variable that i need to send is the url value):

    def choose_cat(self):
        keep_going=True
        while keep_going:
            while loop:
                if ui.output_url():
                    url = ui.output_url()
                    response = urlopen(URL_DICT[url])
                    data = json.loads(response.read())["results"]
                    while data:
                        new_q = random.choice(data)
                        data.remove(new_q)
                        self.question_data.append(new_q)
                    print(self.question_data)
                    return self.question_data
code from ui class (this is only the selected function that gets loaded as soon as the command button is trigerred)

    def output_url(self):
        return self.value_inside.get()
deanhystad write Aug-24-2023, 03:35 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#6
When is choose_cat() called?

And why are there loops in choose_cat? Either you can open a URL of questions, or you can't. If you can't, return an empty list. Eventually the user will select something a cagegory and ui.output_url will return a url. When that happens is when choose_cat() should be called. I would write choose_cat() like this:
import requests
import random

def choose_cat(self):
    """Return a list of random questions from the selected URL, or an empty list."""
    if url := ui.output_url():
        results = requests.get(URL_DICT[url]).json()["results"]
        random.shuffle(results)
        return results
    return []
If the function is called before a url is selected (should not happen) an empty list gets returned. Think of that as the failsafe. This function should only be called when the user selects a url. That should call a function to update the questions, and that code should call choose_cat() to get the questions.

In GUI programming, everything happens as a response to a user action.
Reply
#7
(Aug-24-2023, 06:19 PM)deanhystad Wrote: When is choose_cat() called?

And why are there loops in choose_cat? Either you can open a URL of questions, or you can't. If you can't, return an empty list. Eventually the user will select something a cagegory and ui.output_url will return a url. When that happens is when choose_cat() should be called. I would write choose_cat() like this:
import requests
import random

def choose_cat(self):
    """Return a list of random questions from the selected URL, or an empty list."""
    if url := ui.output_url():
        results = requests.get(URL_DICT[url]).json()["results"]
        random.shuffle(results)
        return results
    return []
If the function is called before a url is selected (should not happen) an empty list gets returned. Think of that as the failsafe. This function should only be called when the user selects a url. That should call a function to update the questions, and that code should call choose_cat() to get the questions.

In GUI programming, everything happens as a response to a user action.

i tried to call the choose cat from the UI py file instead of the data py file in order to get the input from the function into the data py file. i used while loops so that the function in data would get triggered by the function in the UI file. How would i do the initialization of the classes? Cause i need to generate the list of questions from the ui to the data file and use that list to generate questions in a quiz_brain py file and print them on the canvas in the ui py file. How would i get about to do that?
Reply
#8
You do not generate anything until a category is selected. Maybe this example will help.
import random
import tkinter as tk


categories = {
    "History": [f"History Question {i}" for i in range(1, 6)],
    "Literature": [f"Literature Question {i}" for i in range(1, 6)],
    "Math": [f"Math Question {i}" for i in range(1, 6)],
    "Geography": [f"Geography Question {i}" for i in range(1, 6)],
}

def choose_cat(category):
    """Select category from dictionary for demo purposes."""
    if category in categories:
        results = categories[category]
        random.shuffle(results)
        return results
    return []  # <-- This is the fallback.  Caller should handle an empty list

class Window(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.questions = []
        self.category = tk.StringVar()
        self.category.set("Select a Category")
        self.question = tk.StringVar()
        self.answer = tk.StringVar()
        choices = tk.OptionMenu(
            self, self.category, *categories, command=self.select_category
        )
        entry = tk.Entry(self, textvariable=self.answer, width=50)
        entry.bind("<Return>", self.check_answer)

        label = tk.Label(self, textvariable=self.question, width=50)

        choices.pack(padx=10, pady=10)
        label.pack(padx=10, pady=10)
        entry.pack(padx=10, pady=10)

        self.select_category

    def select_category(self, _):
        """Category option menu callback."""
        self.questions = iter(choose_cat(self.category.get()))
        self.next_question()

    def check_answer(self, *_):
        """Pretends to check answer.  Goes on to next question."""
        self.next_question()

    def next_question(self):
        """Displays next question from category."""
        try:
            question = next(self.questions)
        except StopIteration:
            # Don't crash if there are no questions remaining
            question = "Section Complete.  Select new category"
        self.question.set(question)
        self.answer.set("")


Window().mainloop()
No questions are displayed until the category is selected. Selecting the category is what retrieves the questions and updates the panel. Selecting a category from the option menu calls Window.select_category(). Window.select_category calls the function that gets the new questions, and then calls Window.next_question() to update the window controls. Everything in your program should be in response to the user doing something with a control.
Reply
#9
(Aug-24-2023, 07:24 PM)deanhystad Wrote: You do not generate anything until a category is selected. Maybe this example will help.
import random
import tkinter as tk


categories = {
    "History": [f"History Question {i}" for i in range(1, 6)],
    "Literature": [f"Literature Question {i}" for i in range(1, 6)],
    "Math": [f"Math Question {i}" for i in range(1, 6)],
    "Geography": [f"Geography Question {i}" for i in range(1, 6)],
}

def choose_cat(category):
    """Select category from dictionary for demo purposes."""
    if category in categories:
        results = categories[category]
        random.shuffle(results)
        return results
    return []  # <-- This is the fallback.  Caller should handle an empty list

class Window(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.questions = []
        self.category = tk.StringVar()
        self.category.set("Select a Category")
        self.question = tk.StringVar()
        self.answer = tk.StringVar()
        choices = tk.OptionMenu(
            self, self.category, *categories, command=self.select_category
        )
        entry = tk.Entry(self, textvariable=self.answer, width=50)
        entry.bind("<Return>", self.check_answer)

        label = tk.Label(self, textvariable=self.question, width=50)

        choices.pack(padx=10, pady=10)
        label.pack(padx=10, pady=10)
        entry.pack(padx=10, pady=10)

        self.select_category

    def select_category(self, _):
        """Category option menu callback."""
        self.questions = iter(choose_cat(self.category.get()))
        self.next_question()

    def check_answer(self, *_):
        """Pretends to check answer.  Goes on to next question."""
        self.next_question()

    def next_question(self):
        """Displays next question from category."""
        try:
            question = next(self.questions)
        except StopIteration:
            # Don't crash if there are no questions remaining
            question = "Section Complete.  Select new category"
        self.question.set(question)
        self.answer.set("")


Window().mainloop()
No questions are displayed until the category is selected. Selecting the category is what retrieves the questions and updates the panel. Selecting a category from the option menu calls Window.select_category(). Window.select_category calls the function that gets the new questions, and then calls Window.next_question() to update the window controls. Everything in your program should be in response to the user doing something with a control.

basically i have the question data generated in the Data py file transferred over to the Main py file which sends the list to the quizbrain file. Currently i have a function in the quiz brain file to generate a question and another function to check user answer vs the correct answer. Now the problem is that in order to send the user answer from the Gui py file to the quiz_brain file i need to import the Gui class into the quizbrain file. However i also need to send the generated question from the quiz brain file to the Gui file in order to write the question as a canvas text object. But thinking about it it means that im going to have a loop from the Gui file to the quiz brain file so maybe i have to create another function to check the user answer?
also how do i send the question data list from the main file to both the quiz brain file and the answer checker file. FInally how do i coordinate to get the same question and answer variables from the data file to the quiz brain and the answer checker file?
also hopefully one last thing im not clear on is how do i send the optionmenu function to the data file function?
Reply
#10
You have not provided enough context for me to answer your questions. I will make some wild guesses.

Your GUI (I think you call this Main) should know about the Quiz Brain.
The Quiz Brain should know about the Quiz Data.
I don't know if the GUI needs to know about the Quiz Data. Sounds like the Quiz Data is something only the Quiz Brain needs to know about.
Neither the Quiz Brain nor the Quiz Data should know anything about the GUI.

Quote:Now the problem is that in order to send the user answer from the Gui py file to the quiz_brain file i need to import the Gui class into the quizbrain file
When the user has answered the question. I have no idea what form the questions are, so I don't know what this entails. Is it multiple choice and they click a radio button? Do they enter text? Somehow you bind a function to the control(s) used to answer the question. This function sends the answer to the quiz brain. The quiz brain reply should contain enough information for the GUI to produce some response for the user. Maybe display "That is Correct!" or "Sorry, the correct answer is..."

Quote:However i also need to send the generated question from the quiz brain file to the Gui file in order to write the question as a canvas text object.
No you don't. The GUI should ask the quiz brain for the next question.

Quote:also how do i send the question data list from the main file to both the quiz brain file and the answer checker file
You don't. My guess is the question data list comes from the Quiz Data. The player selects a category in the GUI. The GUI tells the Quiz Brain what category of questions the player selected. The Quiz Brain tells Quiz Data to retrieve questions for that category. The GUI asks the Quiz Brain for the first question to display.

Notice how everything starts from the user. Quiz Data never calls something in the GUI. Quiz Brain never calls anything in the GUI. Their jobs are providing questions for the GUI to display, and checking the answers the players provide.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] Not able to use the output from one function into another function AravindPandian 1 1,671 Oct-17-2019, 08:40 AM
Last Post: Evil_Patrick

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020