Legends ofPythos
Claim your name
Objects and Classes

Loki, the Shapeshifter

The last fight of this track

Boss · level 15

Loki

the Shapeshifter

Health4 of 4 stages standing
Loki has taken the shapes of a salmon, a mare and a fly, and slipped every net the gods ever made. To pin him down you must model every form he takes so exactly that he has nowhere left to hide. Objects are nets. Build them well.

The fight

Four stages, each building on the last. Every stage opens with your finished code from the stage before, so you pick up where you left off. This fight draws on classes, inheritance, super(), your own iterators, properties and dataclasses.
Stage 1: The first form. Model one form Loki takes.
Stage 2: The shapes. Give each of Loki's shapes its own way of moving.
Stage 3: The net. Hold every form and walk through them.
Stage 4: The binding. Pin Loki down and keep count of his mischief.

The fight

0 of 4 stages won

Stage 1 of 4

+60 XP
Write a class Form whose __init__(self, name, speed) stores both values as the attributes name and speed. Give it a method move() that returns f'{self.name} moves at {self.speed}', a __repr__ that returns f'Form({self.name!r}, {self.speed!r})' (the !r shows each value the way repr would, so strings keep their quotes), and an __eq__ that treats two forms as equal when their names and speeds match and returns NotImplemented when the other object is not a Form. For example, repr(Form('mare', 9)) is "Form('mare', 9)".
class Form:
    def __init__(self, name, speed):
        # Store name and speed
        pass


    # move, __repr__ and __eq__ go here

Run your code to check it against the tests.

Stage 2 of 4

+60 XP
Keep Form and write three subclasses: Salmon, Mare and Fly. Each one's __init__ takes only speed and calls super().__init__() with its own name: 'salmon', 'mare' or 'fly'. Each overrides move(): a salmon returns f'{self.name} swims at {self.speed}', a mare f'{self.name} gallops at {self.speed}' and a fly f'{self.name} buzzes at {self.speed}'. For example, Mare(9).move() is 'mare gallops at 9', and Mare(9) == Form('mare', 9) is True.
class Form:
    def __init__(self, name, speed):
        self.name = name
        self.speed = speed


    def move(self):
        return f'{self.name} moves at {self.speed}'


    def __repr__(self):
        return f'Form({self.name!r}, {self.speed!r})'


    def __eq__(self, other):
        if not isinstance(other, Form):
            return NotImplemented
        return self.name == other.name and self.speed == other.speed




class Salmon(Form):
    # __init__(self, speed) and move
    pass




class Mare(Form):
    pass




class Fly(Form):
    pass

Run your code to check it against the tests.

Stage 3 of 4

+60 XP
Keep everything and write three more classes. NoSuchForm is an exception. ShiftIterator takes a list of forms and hands them out one at a time: its __next__ returns the next form and raises StopIteration when there are none left, and its __iter__ returns the iterator itself. Shapeshifter takes a list of forms in __init__, supports len(), and its __iter__ returns a new ShiftIterator over its forms, so a shapeshifter can be looped over more than once. Its method shift(name) returns the first form with that name, or raises NoSuchForm if there is none. For example, [f.name for f in Shapeshifter([Salmon(3), Fly(2)])] is ['salmon', 'fly'].
class Form:
    def __init__(self, name, speed):
        self.name = name
        self.speed = speed


    def move(self):
        return f'{self.name} moves at {self.speed}'


    def __repr__(self):
        return f'Form({self.name!r}, {self.speed!r})'


    def __eq__(self, other):
        if not isinstance(other, Form):
            return NotImplemented
        return self.name == other.name and self.speed == other.speed




class Salmon(Form):
    def __init__(self, speed):
        super().__init__('salmon', speed)


    def move(self):
        return f'{self.name} swims at {self.speed}'




class Mare(Form):
    def __init__(self, speed):
        super().__init__('mare', speed)


    def move(self):
        return f'{self.name} gallops at {self.speed}'




class Fly(Form):
    def __init__(self, speed):
        super().__init__('fly', speed)

Run your code to check it against the tests.

Stage 4 of 4

+60 XP
Keep everything. Write a dataclass Trick with the fields name: str and cost: int = 1. Then write class Loki(Shapeshifter), which starts with a mischief of 0. mischief is a property whose setter raises ValueError for a negative value. Loki's method play(trick) adds the trick's cost to his mischief and returns the new total. For example, a new Loki that plays Trick('net') and then Trick('mistletoe', 5) gets 1 and then 6.
class Form:
    def __init__(self, name, speed):
        self.name = name
        self.speed = speed


    def move(self):
        return f'{self.name} moves at {self.speed}'


    def __repr__(self):
        return f'Form({self.name!r}, {self.speed!r})'


    def __eq__(self, other):
        if not isinstance(other, Form):
            return NotImplemented
        return self.name == other.name and self.speed == other.speed




class Salmon(Form):
    def __init__(self, speed):
        super().__init__('salmon', speed)


    def move(self):
        return f'{self.name} swims at {self.speed}'




class Mare(Form):
    def __init__(self, speed):
        super().__init__('mare', speed)


    def move(self):
        return f'{self.name} gallops at {self.speed}'




class Fly(Form):
    def __init__(self, speed):
        super().__init__('fly', speed)

Run your code to check it against the tests.