This is the third time I am asking for a review of this code (first time can be found here: Arabic language lesson program and the second can be found here: Arabic language lesson program Part 2).

The goal of the program is to house Arabic language lessons and teach Arabic to English speakers, somewhat similar to how Duolingo works.

The first time around I was instructed to move the questions out of the code and into a separate text file. Now all my questions are sorted by lesson number and part number into a .json file and I call certain questions from the file in the code. In the second round of reviews, I learned how to use for loops to consolidate a significant amount of my code. Though I've been able to greatly reduce the amount of repetition in my code, I still would like to move my code into a class based system. Eventually I plan on having 50 to 100 questions housed in several lessons each with multiple part so I want to be as efficient as possible in my coding to make code maintenance as manageable as I can.

Review Objective: I would like help figuring out how to take my current code and migrate it into a more manageable setup (I'm assuming something class-based) that would allow me to continue to build this program in a manageable fashion. Also, would it be worth having a separate python file for each lesson and then have a main python program to tie them all together or would it be better to just have one large python program? Any advice would be appreciated.

def Part1():
    Root_File_Name = "C:\\LearningArabic\\LiblibArriby\\"

    JSON_File = Root_File_Name + "Lessons\\Lesson_1\\"
    with open(JSON_File+"Arabic_Lesson_1.json", "r", encoding = "utf-8-sig") as question_file:   
        data = json.load(question_file)              

    def create_widgets_in_first_frame():        # Create the label for the frame
        current_frame=frames[0]               #Make the frame number generic so as to make copy/paste easier. ##UPDATE PER QUESTION##
        question_number = "question0"

        question_frame_populator(current_frame, question_number)

    def question_frame_populator(current_frame, question_number): #This is what displayes all of the information on the frame
        questionDirectory = data["lesson 1"]["part one"][question_number]       ##UPDATE PER QUESTION##  This is the directory for the question.
        wronganswer = questionDirectory["wronganswer"]                      #This is the directory for the wrong answers
        question = questionDirectory.get("question")                        #This is the question text            
        correctanswer = questionDirectory.get("answer")                     #This is the answer for whichever question has been selected.
        arabic = questionDirectory.get("arabic")                            #This is the arabic text for the question
        transliteration = questionDirectory.get("transliteration")

        global var
        var = IntVar()
        var.set(0)  #Sets the initial radiobutton selection to nothing

        answers = generate_answers(wronganswer, correctanswer)  #Pulls answers generated from the "generate_answers" function
        choices = []
        for i in range(3):
            choice = Radiobutton(current_frame, image=answers[i], variable = var, value=i+1, command= Check_Answer)
            choice.image = answers[i]

        random.shuffle(choices) #This line of code randomizes the order of the radiobuttons. 
        choices[0].grid(row=1, column=0)
        choices[1].grid(row=1, column=1)
        choices[2].grid(row=1, column=2)

        L1 = Label(current_frame, text=question, font=("Helvetica", 35))    #This displays the question at the top of the screen
        L1.grid(columnspan=4, row=0)

        transliteration_button = Button(current_frame, text="Show Transliteration", command= lambda: Transliteration(current_frame, arabic, transliteration))    # Makes the phonetic pronunciation button. #####
        transliteration_button.grid(column=0, row=2)

        #Previous_Button() # Creates the "previous" button and displays it.
        Next_Button()  # Creates the "next" button and displays it.
        Quit_Button(current_frame)  # Creates the "quit" button and displays it.

    def Transliteration(current_frame, arabic, transliteration):
        Transliteration = Label(current_frame, text="'"+arabic+"'" + " is pronounced " + "'"+transliteration+"'", font=("Helvetica", 35))
        Transliteration.grid(row=3, columnspan=4)

    def generate_answers(wronganswer, correctanswer):
        Wans=random.sample(wronganswer, 2)
        images = [os.path.join(ImagePath, f"{Wans[i]}.png") for i in range(2)]
        images += [os.path.join(ImagePath, f"{correctanswer}.png")]
        answers = [PhotoImage(file=images[i]) for i in range(3)]
        return answers

    def Check_Answer():
        global lives
        global score

        if str(var.get()) !="3":
            special_frames[1].grid_forget() #This is the frame for right answers
            special_frames[0].grid(column=1, row=0, padx=20, pady=5, sticky=(tkinter.W, tkinter.E)) #This is the frame for wrong answers
            lives -=1

            Incorrect = Label(special_frames[0], text ="That's incorrect!\n Lives: " +str(lives) + "\n Score: " + str(score), font=("Helvetica", 35))
            Incorrect.grid(row=0, rowspan=2, column=0, columnspan=3)

        if str(var.get()) == "3":
            score +=1

            special_frames[0].grid_forget() #This is the frame for wrong answers
            special_frames[1].grid(column=1, row=0, padx=20, pady=5, sticky=(tkinter.W, tkinter.E)) #This is the frame for right answers

            Correct = Label(special_frames[1], text = "    That's right!    \n Lives: " +str(lives)+ "\n Score: " + str(score), font=("Helvetica", 35))
            Correct.grid(row=0, rowspan=2, column=0, columnspan=5)

    def all_frames_forget():
        for i in range(6):  #This is for question frames
        for i in range(3):  #This is for special frames, like the correct and incorrect answer frames

    def check_remaining_lives(create_widgets_in_current_frame, current_frame):
        if lives<= 0:
            current_frame.grid(column=0, row=0, padx=20, pady=5, sticky=(tkinter.W, tkinter.N, tkinter.E))

    def Zero_Lives():
        special_frames[2].grid(column=0, row=0, padx=20, pady=5, sticky=(tkinter.W, tkinter.E))

        L5 = Label(special_frames[2], text="You have no remaining lives. \nPlease quit the lesson and try again.", font=("Helvetica", 35))
        L5.grid(columnspan=4, row=0)

        quit_button = Button(special_frames[2], text = "Quit", command = root_window.destroy)
        quit_button.grid(column=1, columnspan = 2, row=2)

    def Quit_Button(current_frame):
        quit_button = Button(current_frame, text = "Quit", command = quit_program)
        quit_button.grid(column=4, row=2)

    def quit_program():

    def Next_Button():
        next_button = Button(special_frames[1], text = "Next Question", command = next_question)
        next_button.grid(column=0, columnspan=5, row=3)

    def next_question():
        global frameNumber
        frameNumber +=1


    def create_widgets_function(frameNumber):
        current_frame=frames[frameNumber]               #Make the frame number generic so as to make copy/paste easier. ##UPDATE PER QUESTION##

        question_number = "question"+ str(frameNumber)
        question_frame_populator(current_frame, question_number)

    def call_frame(frameNumber):
        create_widgets_in_current_frame =create_widgets_function(frameNumber)
        current_frame = frames[frameNumber]
        check_remaining_lives(create_widgets_in_current_frame, current_frame)

    def call_frame_1():
        create_widgets_in_current_frame = create_widgets_in_first_frame() #This line is unique
        current_frame = frames[0]     #This line is unique
        check_remaining_lives(create_widgets_in_current_frame, current_frame)        

    ##### Program starts here  #####
    Lesson1_FilePath = Root_File_Name + "Lessons\\Lesson_1\\"
    ImagePath = Lesson1_FilePath + "Images\\"

    root_window = Tk() # Create the root GUI window.
    root_window.title("Lesson 1: Part 1") # Label the root GUI window.

    global score
    score = 0               #Setting the initial score to zero.
    global lives
    lives = 3               #Setting the initial number of lives.
    global frameNumber
    frameNumber = 1

    window_width = 200      # Define window size
    window_heigth = 100

    frames = []  # This includes frames for all questions
    for i in range(6):
        frame=tkinter.Frame(root_window, width=window_width, height=window_heigth)
        frame['borderwidth'] = 2
        frame['relief'] = 'sunken'
        frame.grid(column=0, row=0, padx=20, pady=5, sticky=(tkinter.W, tkinter.N, tkinter.E))

    special_frames=[] #This includes the frames for: wrong answers, right answers, and zero lives
    for i in range(3):
        special=tkinter.Frame(root_window, width=window_width, height=window_heigth)
        special['borderwidth'] = 2
        special['relief'] = 'sunken'
        special.grid(column=1, row=0, padx=20, pady=5, sticky=(tkinter.W, tkinter.E))

    call_frame_1() #Calls the first function which creates the firist frame


Here is a section of my .json file fore reference:

{"lesson 1":
        {"part one": {
                "question0": {
                        "question": "What is the meaning of 'واد' in English?",
                        "arabic": "واد",
                        "transliteration": "walid",
                        "answer": "boy",
                        "wronganswer" : [
                                "girl", "woman", "man", "waiter", "mom", "priest", 

"driver", "teacher", "doctor", "grandparents", "chef"
                "question1": {
                        "question": "What is the meaning of 'بنت' in English?",
                        "arabic": "بنت",
                        "transliteration": "bint",
                        "answer": "girl",
                        "wronganswer" : [
                                "woman", "man", "waiter", "mom", "priest", 

"driver", "teacher", "doctor", "grandparents", "Chef"
                "question2": {
                        "question": "What is: 'He is a boy' in Arabic?",
                        "arabic": "هو ولد",
                        "transliteration": "Huwa walid",
                        "answer": "Heboy",
                        "wronganswer" : [
                "question3": {
                        "question": "What is: 'She is a girl' in Arabic?",
                        "arabic": "هي بنت",
                        "transliteration": "Hia bint",
                        "answer": "Shegirl",
                        "wronganswer" : [
                "question4": {
                        "question": "What is the meaning of 'ست' in English?",
                        "arabic": "ست",
                        "transliteration": "sit",
                        "answer": "woman",
                        "wronganswer" : [
                        "girl", "boy", "man", "waiter", "mom", "priest", "driver", 

"teacher", "doctor", "grandparents", "Chef"
                "question5": {
                        "question": "What is the meaning of 'رخل' in English?",
                        "arabic": "رخل",
                        "transliteration": "ragul",
                        "answer": "man",
                        "wronganswer" : [
                                "girl", "woman", "boy", "waiter", "mom", "priest", 

"driver", "teacher", "doctor", "grandparents", "Chef"

Here is an example of one of the questions:

enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.