Object oriented hangman game
It might be slightly cleaner and more performant to keep self.mask as a list, and just join it before printing:

# Basically what you had before, without the space
# Just "list multiplication" instead of "string multiplication"
self.mask = ['_'] * len(word)

. . .

if w == letter:
    mask[i] = letter

. . .

if '_' not in self.mask:
    self.show_board()
    print('You won!')

. . .

print(' '.join(self.mask))


Now there's less converting back and forth between strings and lists. This also saves you from needing to do i * 2. The spaces can just be added in using join before being printed, so you don't need to worry about them.



print(self.mistakes) currently prints out a normal list representation to the end user without any context. I'd probably prefix a message to that, and format it a bit before printing:

print(f"Already tried: {', '.join(self.mistakes)}")
# Already tried: R, Q




I'd probably get rid of self.winner and change how you're checking for winning. Notice what you're using it for: you assign it in check_winner, then return that same value that you just assigned, but never use the return value. I'd have check_winner just return the value, move the call to check_winner to after the call to make_move, and use the return value:

def check_winner(self):
    if '_' not in self.mask:
        self.show_board()
        print('You won!')
        return True

    return False

. . .

def play(self):
    won = False  # Just track this locally instead

    while not won:
        self.show_board()

        letter_input = input('Choose a letter: ').upper()
        self.make_move(letter_input)

        won = self.check_winner()  # And assign it here
        self.check_loser()


I'd also probably change check_loser (As a heads up, it's spelled "loser". "Looser" means that one thing is "less tight" than something else). I'd maybe have it return a bool saying whether or not the player lost, and just return from that function instead. As I noted in a previous review (at the bottom), quit can cause problems when testing code. Just returning from the main loop to allow control to pass back to the REPL is much cleaner.