9

I have a base class that represents the state of a game and provides a perform_move method:

class GameState:
  # other code
  def perform_move(self, position: LinePosition) -> MoveResult:
    # more code

Now I want to create a subclass of GameState that keeps track of the players' score. Because the base class doesn't care about players (separation of concerns), I need an additional argument to identify the player that is performing the move. I tried the following:

class ScoreKeepingGameState(GameState):
  # other code
  def perform_move(self, position: LinePosition, *, player_identification: Optional[int] = None) -> MoveResult:
    # more code

I expected this to work, since I can call ScoreKeepingGameState's perform_move perfectly fine without the player_identification, alas pylint complains:

W0221: Parameters differ from overridden 'perform_move' method (arguments-differ)

Is there a cleaner approach to satisfy pylint than adding # pylint: disable=arguments-differ to the perform_move definition of ScoreKeepingGameState?

GitProphet
  • 870
  • 1
  • 12
  • 22
  • It does seem like a bug because the docs say "Extra arguments with default values are ignored." which they are clearly ... not. – coler-j Nov 15 '22 at 18:08

1 Answers1

3

There's some quick and direct ways, and then there's the way where you rethink the design and use of inheritance.

The quick way: Make perform_move in the base class accept *args and **kwargs arguments; then the inheriting class also just accepts *args and **kwargs and it all will work. I don't like it that much because we lose the function signature that way, but it will make pylint stop complaining.

The longer way: If GameState shouldn't concern itself with player scores, then I assume it has some other single responsibility. Subclasses of GameState will still have that same responsibility; they're just fulfilling it in a different way. But now you also make it responsible for calculating and keeping track of the player's score. At least I assume that's what the overriden version of perform_move is supposed to do.

So maybe you want a separate class ScoreKeeper just for tracking score, and it shouldn't inherit from GameState.

Then you'd have a class responsible for "handling" player moves. This class would communicate separately with GameState to tell it about the line position and with ScoreKeeper to tell it about the player.

cadolphs
  • 9,014
  • 1
  • 24
  • 41