Python clean code

whitehousechef·2025년 6월 24일

Optional

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...except

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

infinite loop until break

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.")

diff between break and return

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

try...continue

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

formatting cinema

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)

constructor mistake

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

infinite loop

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()

enum

# 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

init optional/default fields

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

try ... except

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")

returning immediately in for loop

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!

0개의 댓글