Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I have to implement all abstract methods in python 2.7?

I'm adapting the text adventure game tutorial, github, to fit python 2.7. I'm using the PyCharm 4.5.4 community edition for my IDE. When I don't override a parent method it gives me an error:

Class WolfRoom must implement all abstract methods

At first to get rid of this error I defined the missing method def modify_player(self, the_player): as pass but I quickly realized I was overriding the method with nothing which isn't what I wanted. Now if I just remove the method from the WolfRoom class I get an IDE error, as seen above, but it appears to work just fine when I run my game. Should I leave this method out or define it and use super()?

Here are some code snippets:

class MapTile(object):
    """The base class for all Map Tiles"""

    def __init__(self, x, y):
        """Creates a new tile.
        Attributes:
            :param x: The x coordinate of the tile.
            :param y: The y coordinate of the tile.
        """
        self.x = x
        self.y = y

    def intro_text(self):
        """Information to be displayed when the player moves into this tile."""
        raise NotImplementedError()

    def modify_player(self, the_player):
        """Process actions that change the state of the player."""
        raise NotImplementedError()

    def adjacent_moves(self):
        """Returns all move actions for adjacent tiles."""
        moves = []
        if world.tile_exists(self.x + 1, self.y):
            moves.append(actions.MoveEast())
        if world.tile_exists(self.x - 1, self.y):
            moves.append(actions.MoveWest())
        if world.tile_exists(self.x, self.y - 1):
            moves.append(actions.MoveNorth())
        if world.tile_exists(self.x, self.y + 1):
            moves.append(actions.MoveSouth())
        return moves

    def available_actions(self):
        """Returns all of the available actions in this room"""
        moves = self.adjacent_moves()
        moves.append(actions.ViewInventory())
        return moves

...

class EnemyRoom(MapTile):
    def __init__(self, x, y, enemy):
        self.enemy = enemy
        super(EnemyRoom, self).__init__(x, y)

    def intro_text(self):
        pass

    def modify_player(self, the_player):
        if self.enemy.is_alive():
            the_player.hp = the_player.hp - self.enemy.damage
            print("Enemy does {} damage. You have {} HP remaining.".format(self.enemy.damage, the_player.hp))

    def available_actions(self):
        if self.enemy.is_alive():
            return [actions.Flee(tile=self), actions.Attack(enemy=self.enemy)]
        else:
            return self.adjacent_moves()

...

class WolfRoom(EnemyRoom):
    def __init__(self, x, y):
        super(WolfRoom, self).__init__(x, y, enemies.Wolf())

    def intro_text(self):
        if self.enemy.is_alive():
            return """
            A grey wolf blocks your path. His lips curl to expose canines as white as
            the nights sky. He crouches and prepares to lunge.
            """
        else:
            return"""
            The corpse of a grey wolf lays rotting on the ground.
            """
like image 681
Zach Avatar asked Dec 05 '22 20:12

Zach


1 Answers

I believe this is actually due to the PyCharm inspector making an error, or at least a dubious decision regarding PEP 8 style, when looking to see if there are any non-implemented methods which will raise a NotImplementedError. Consider this simpler example which is very similar:

class Base(object):
    def foo(self):
        raise NotImplementedError

    def bar(self):
        return 0

class Child(Base):
    def foo(self):
        return 0

class GrandChild(Child):
    def bar(self):
        return 1

my_grand_child = GrandChild()
print my_grand_child.foo()

The above code successfully prints a 0 to the output, because when Python can't find the implementation of foo() in GrandChild it looks up the inheritance chain and finds it in Child. However, for some reason the PyCharm inspector expects all classes which raise NotImplementedError to be implemented in ALL levels of the inheritance chain.

If you were to follow this style in programs with large inheritance structures, you would find yourself being extremely verbose by implementing methods and making calls to super all throughout the chain, when it simply isn't required. Personally, I just ignore the error, and think that PyCharm should be updated to not show it if it finds the method implemented in any superclass of the class it is inspecting.

like image 171
Coxy Avatar answered Dec 22 '22 15:12

Coxy