when declaring optional parameter, u need to equate it to None to assign default value. Cuz without =None, that start_pos parameter becomes compulsory argument.
start_position:Optional[str] = None
try:
row_idx, col_idx = self._parse_position("invalid_format") # Throws ValueError
# This line never executes ↓
if not cinema.is_valid_position(row_idx, col_idx):
return []
except ValueError:
return [] # ← Execution jumps here
we encase everything in while True, which creates an infinite loop which is broken only by the break.
The purpose of try...except inside a while loop is to handle the error and allow the loop to continue gracefully, rather than crashing or breaking.
while True:
try:
user_input = input("Enter a number (or 'quit' to exit): ")
if user_input.lower() == 'quit':
print("Exiting loop.")
break # This is what breaks the loop for 'quit'
number = int(user_input) # This line can raise a ValueError
print(f"You entered: {number}")
except ValueError:
print("That's not a valid number. Please try again.")
# The loop *continues* from here, going back to the 'while True' check.
except Exception as e:
print(f"An unexpected error occurred: {e}")
# The loop *continues* from here as well.
finally:
print("--- End of current attempt ---")
print("Program finished.")
in while True loop, if u break, u still continue processing code after the while loop. But if u place return, it stops processing all the code in that function and returns. Like even if theres code after the while loop it doesnt run that
here try is like a for loop. continue goes to next iteration so code is still stuck within try block.
try: # <--- Start of try block
num_tickets = int(user_input)
if num_tickets <= 0:
print("Please enter a positive number of tickets")
continue # <--- continue within try
f"{seat_char:^{col_width}}" means:
"Take the value of seat_char, and format it so that it is centered within a field that is col_width characters wide. If seat_char is shorter than col_width, pad the remaining space evenly on both sides with spaces."
Examples:
Let's assume col_width = 3 for these examples:
seat_char = 'O' (Available Seat)
f"{'O':^3}"
'O' is 1 character long. col_width is 3.
Remaining space: 3 - 1 = 2 characters.
These 2 characters are distributed as evenly as possible around 'O'.
Result: " O " (1 space on left, 1 space on right)
class Cinema:
def __init__(self, movie_title:str, total_rows:int, seats_per_row:int,
seat_allocation_strategy: SeatAllocationStrategy = None):
self._validate_configuration(movie_title,total_rows,seats_per_row)
self.total_rows = total_rows
self.seats_per_row = seats_per_row
self._seats = self._initialise_seats()
self.movie_title = movie_title
self._allocationStrategy = seat_allocation_strategy or DefaultSeatAllocationStrategy
self._booking_counter = 1
self._bookings:Dict[str,Booking] = {}
notice for _allocationStrategy, I am not passing a instance of DefaultSeatAllocationStrategy cuz I didnt put () at the end. This is passing the class, not instance.
So
1)When you call self._allocationStrategy.allocate_seats(...), you're calling it on the class
2) The class method gets called with the wrong self - it receives the Cinema instance instead of a DefaultSeatAllocationStrategy instance
3) When the method tries to call self._allocate_default(...), it's looking for that method on the Cinema object
4) Since Cinema doesn't have _allocate_default, you get the AttributeError
wrong code
def run(self):
"""run the main application logic"""
try:
self.display_main_menu()
choice = self._get_user_input()
while True:
if choice=='1':
self._handle_booking()
elif choice=='2':
self._handle_check_booking()
elif choice=='3':
print("\n thanks for choosing gic. bye")
break
else:
print("press 1, 2 or 3")
except KeyboardInterrupt:
print("thanks for using gic! bye")
wat could be the problem like infinite loop
notice that once i try to get the user input's choice, i enter a while loop that keeps on checking this choice value. This is infinite loop. Instead we should get user value choice within while loop
correct:
while True:
self.display_main_menu()
choice = self._get_user_input()
if choice=='1':
self._handle_booking()
# Each enum instance gets the price property
regular_seat = SeatType.REGULAR
print(regular_seat.price) # Calls the property method where self = SeatType.REGULAR
# The property method does:
# 1. self = SeatType.REGULAR
# 2. price_info[SeatType.REGULAR] = 10
# 3. return 10
field(init=False) vs field(default_factory="default something")
field(init=False)
Excludes the field from the init method entirely but
field(default_factory=...)
Includes the field in init but with a default value generator
@dataclass
class Theater:
theater_id: str
total_rows: int
seats_per_row: int
_seats: List[List[Seat]] = field(init=False) # Not in __init__ at all
def __post_init__(self):
self._seats = self._initialize_seats() # You manually set it
# Usage:
theater = Theater("T1", 10, 15) # Only 3 parameters
# theater._seats is set in __post_init__
@dataclass
class MovieShowing:
showing_id: str
movie_title: str
theater: Theater
showtime: datetime
_bookings: Dict[str, Booking] = field(default_factory=dict) # In __init__ with default
# Usage - both work:
showing1 = MovieShowing("S1", "Avatar", theater, datetime.now()) # Uses default empty dict
showing2 = MovieShowing("S1", "Avatar", theater, datetime.now(), {"book1": booking}) # Override default
but why dont we just initialise as like []?
# ❌ DANGEROUS - mutable default argument problem
@dataclass
class BadExample:
name: str
grades: List[int] = [] # Same list shared by ALL instances!
# ✅ SAFE - each instance gets its own list
@dataclass
class GoodExample:
name: str
grades: List[int] = field(default_factory=list) # New list for each instance
Actually there is a case where i thought it will catch the keyboard but it returns immediately. This is cuz there is no blocking action like input().
no need try cuz it returns immediately
def _view_movie(theatre:Theatre):
try:
print("Here are all the movies currently showcased")
print(theatre.list_cinema())
# This line will now pause and wait for the user to press Enter
input("Press enter to return to previous page")
except KeyboardInterrupt:
print("Returning to previous page")
this just returns the fist comb, and is not like a generator function that i was thinking of. Fundamentally in a for loop, once u have a return statement u return and code doesnt run right? Same here but i was confused with combinations function.
def _find_cluster(self, available_seats: List[Seat], num_seats:int) -> tuple[int, ...]:
from itertools import combinations
available_seats_columns = [seat.column for seat in available_seats]
for comb in combinations(available_seats_columns, num_seats):
return comb # ❌ Returns immediately - no comparison!