Current Code Structure:
Main Menu run()
→ _add_movie()
→ system.run()
→ _select_cinema()
Problem: When user presses Enter in _select_cinema(), I want to return all the way back to the Main Menu run(), not just continue in the current method.
Current Issue: The return in _select_cinema() only exits that method, but system.run() continues to display the main menu instead of going back to the Main Menu.
def _select_cinema(self):
try:
print("Enter movie name to buy/update tickets or Press Enter to return to previous page")
user_input_movie_title = self._get_user_input("").strip()
if not user_input_movie_title:
return # THIS ONLY EXITS _select_cinema(), NOT system.run()
self.select_cinema = self.theatre.get_cinema_by_title(user_input_movie_title)
except KeyboardInterrupt:
print("Returning")
def run(self): # This is system.run()
"""Run the main application loop."""
try:
while True:
self._select_cinema() # When this returns, code continues below
self._display_main_menu() # THIS STILL RUNS even when user pressed Enter
choice = self._get_user_input("").strip()
# ... rest of menu logic
except KeyboardInterrupt:
print("\n\nThank you for using GIC Cinemas system. Bye!")
def _add_movie(self, theatre: Theatre):
while True:
# ... movie creation logic ...
system = CinemaBookingSystemFactory.add_cinema_to_theatre(theatre, user_input, tmp_lines)
system.run() # THIS KEEPS RUNNING even when user wants to go back
Concept: Use custom exceptions to "bubble up" navigation commands through the call stack.
# Define custom exceptions
class NavigationException(Exception):
pass
class BackToMainMenuException(NavigationException):
pass
# Modify _select_cinema to throw exception
def _select_cinema(self):
user_input_movie_title = self._get_user_input("").strip()
if not user_input_movie_title: # User pressed Enter
raise BackToMainMenuException()
self.select_cinema = self.theatre.get_cinema_by_title(user_input_movie_title)
# Modify _add_movie to catch and handle
def _add_movie(self, theatre: Theatre):
try:
# ... existing code ...
system.run()
except BackToMainMenuException:
return # Go back to main menu
# system.run() doesn't need to change - exception bubbles up automatically
Pros: Clean, automatically bubbles up through call stack, easy to add more navigation types
Cons: Uses exceptions for control flow (some consider this bad practice)
Exceptions are menat for exception, unforseen situations (errors and failures), not normal program flow. There is also code readability issue and performance issues like
1)Memory allocation for exception objects
2)Call stack inspection
3)Much slower than simple return statements
Concept: Use boolean returns to indicate success/failure, check at each level.
# Modify _select_cinema to return boolean
def _select_cinema(self):
user_input_movie_title = self._get_user_input("").strip()
if not user_input_movie_title: # User pressed Enter
return False # Indicate user wants to go back
self.select_cinema = self.theatre.get_cinema_by_title(user_input_movie_title)
return True # Indicate success
# Modify system.run() to check return value
def run(self): # This is system.run()
while True:
if not self._select_cinema():
return False # User wants to go back
# ... rest of menu logic ...
return True # Normal completion
# Modify _add_movie to check return value
def _add_movie(self, theatre: Theatre):
# ... existing code ...
if not system.run():
return # Go back to main menu
Pros: Simple, explicit, easy to understand
Cons: Need to check return values at each level, more boilerplate code
Option 3 (Boolean) - CLEANEST ✅
def _select_cinema(self):
if not user_input_movie_title:
return False # Clear intent: operation failed
# ... success logic
return True # Clear intent: operation succeeded
Pros:
Option 2 (Exceptions) - LESS CLEAN ❌
def _select_cinema(self):
if not user_input_movie_title:
raise BackToMainMenuException() # Using exceptions for control flow
Cons:
Even Better Option 4 - CLEANEST OVERALL ✅
Use an Enum for even cleaner semantics:
from enum import Enum
class UserAction(Enum):
CONTINUE = "continue"
GO_BACK = "go_back"
EXIT = "exit"
def _select_cinema(self):
if not user_input_movie_title:
return UserAction.GO_BACK
# ... success logic
return UserAction.CONTINUE
def run(self):
while True:
action = self._select_cinema()
if action == UserAction.GO_BACK:
return UserAction.GO_BACK
# ... rest of logic
Why this is cleanest:
UserAction.GO_BACK is crystal clearRanking:
1. Option 4 (Enum) - Best for larger applications
2. Option 3 (Boolean) - Best for simple cases like yours
3. Option 2 (Exceptions) - Avoid for control flow
For your current needs: Use Option 3 (Boolean). It's simple, clean, and perfect for your use case.
once u receive the result from system.run(), you can handle it in your FIRST and outermost run() however you like. But be careful!! I ran system.run() twice with this if elif statement, which doesnt exit the code! Instead, store the result in a variable and do logic onto it
wrong:
system = CinemaBookingSystemFactory.add_cinema_to_theatre(theatre, user_input, tmp_lines)
if system.run() == UserAction.GO_BACK: # ← First call to run()
return
elif system.run() == UserAction.EXIT: # ← Second call to run()
sys.exit(0)
correct:
system = CinemaBookingSystemFactory.add_cinema_to_theatre(theatre, user_input, tmp_lines)
result = system.run() # Call it once and store the result
if result == UserAction.GO_BACK:
return
elif result == UserAction.EXIT:
sys.exit(0)