I am learning python (fairly new) and decided to create a simple rock paper scissors bot as a mini side project to apply the lessons I've learned.

I have encountered an issue during my development:Circular import issue

Based on my understanding and some searches on stackoverflow (specifically this question), this happens due to the imports that I made. My files imports from one another. So when Python tries to load one while the other is unfinished, it crashes with "partially initialized module". I understood it's kind of a structural dependency problem. So my fix was to create another View that these two Views can call instead.

First, here's the logic flow that I did for my bot. I did this portion first, where the user chooses "How to Play", and another view if the user wants to continue or exit:

Logic diagram

What I did was just loop the views. Here are my views. I'll add the relevant code only:

rps_views.py (the view the bot calls first)

import discord, datetime
from game.rock_paper_scissors.utils.game_logic import (
    get_players_choice_value,
    get_bots_choice_value,
    rock_paper_scissors,
    get_state_emoji
)

from game.rock_paper_scissors.views.rps_navigate import (
    RpsNavigate
)

rps_nav_obj = RpsNavigate()

class RpsMainMenuView(discord.ui.View):
    def __init__(self, *, timeout = 180):
        super().__init__(timeout=timeout)

    #How to play
    @discord.ui.button(label="❔How to Play", style=discord.ButtonStyle.primary)
    async def how_to_play(self, btn_interaction: discord.Interaction, button: discord.ui.Button):
        
        await btn_interaction.response.send_message(
            "Classic Rock, Paper, Scissors! Choose between the three, and we'll see if you win against me!",
            view=rps_nav_obj.determine_view("HTP")
        )

how_to_play_views.py

import discord

from game.rock_paper_scissors.views.rps_navigate import (
        RpsNavigate
    )

rps_nav_obj = RpsNavigate()

class HowToPlayView(discord.ui.View):
    def __init__(self, *, timeout: float | None = 180):
        super().__init__(timeout=timeout)
        
    #Continue
    @discord.ui.button(label="✅Continue", style=discord.ButtonStyle.success)
    async def htp_continue(self, btn_interaction: discord.Interaction, button: discord.ui.Button):
        await btn_interaction.response.send_message(
            "Ready to Play Rock Paper Scissors?",
            view=rps_nav_obj.determine_view("RPS")
        )

    
    #Exit
    @discord.ui.button(label="🔚 Exit", style=discord.ButtonStyle.red)
    async def htp_exit(self, btn_interaction:discord.Interaction, button: discord.ui.Button):
        await btn_interaction.response.send_message(
            "Goodbye!"
        )
        

rps_navigate.py , I created this View so that the two can call this instead of being dependent on each other.

import discord
class RpsNavigate(discord.ui.View):
    def __init__(self):
        self = self
        
        
    def determine_view(self, view_choice):
        self.view_choice = view_choice
        print(f"[RPS Navigate] Determining views to be passed: {self.view_choice}")

        #initialize views
        print("Initializing views...")
        from game.rock_paper_scissors.views.rps_views import (
                    RpsMainMenuView,
                    RpsMovesView
                )
        
        from game.rock_paper_scissors.views.how_to_play_views import (
                    HowToPlayView
                )
        rps_main_menu_view = RpsMainMenuView()
        how_to_play_view = HowToPlayView()
        rps_moves_view = RpsMovesView()


        if self.view_choice == "RPS":
            return rps_main_menu_view
        elif self.view_choice == "HTP":
            return how_to_play_view
        elif self.view_choice == "RMV":
            return rps_moves_view
        else:
            return rps_main_menu_view
        

Since I mentioned earlier that rps_view.py is the first view my bot calls, I still encounter the circular issue import if I put the imports in the second line of rps_navigate.py. So I figured I'd add it inside the determine_view method. And my bot works perfectly. My question is, is there a better way to do this? Maybe it's because I'm also from Java, and I'm used that imports are at the top of the classes. Any advice and tips are appreciated!