{"id":"inheritance-overriding","slug":"overriding","title":"Overriding methods","text":"A derived class can also change a method it inherits. Write a method with the same name in the derived class, and objects of that class use the new version instead. This is called **overriding** the method.\n\nSay knights wear armor that stops half of every hit:\n\n```python\nclass Character:\n    def __init__(self, name, health):\n        self.name = name\n        self.health = health\n\n    def take_damage(self, amount):\n        self.health -= amount\n\n    def __str__(self):\n        return f\"{self.name} ({self.health} health)\"\n\n\nclass Knight(Character):\n    def take_damage(self, amount):\n        # The armor stops half of every hit.\n        self.health -= amount // 2\n\n\nbram = Knight(\"Bram\", 50)\npip = Character(\"Pip\", 50)\nbram.take_damage(20)\npip.take_damage(20)\nprint(bram)\nprint(pip)\n```\n\n```output\nBram (40 health)\nPip (30 health)\n```\n\nWhen you call a method, Python first looks for it in the object's own class, and only if it isn't there, in the base class. `bram` is a `Knight`, and `Knight` has its own `take_damage`, so that's the one that runs. `pip` is a plain `Character`, so the original runs. `__str__` isn't overridden, so both use the one in `Character`. It's a method like any other, though: a derived class can override `__str__` too.\n\n### The base class calls the new version\n\nOverriding reaches further than the calls you write yourself. When a method of the base class calls `self.something()`, and the object belongs to a derived class that overrides `something`, the overriding version runs:\n\n```python\nclass Greeter:\n    def greeting(self, name):\n        return f\"Hello, {name}.\"\n\n    def greet_all(self, names):\n        for name in names:\n            print(self.greeting(name))\n\n\nclass PirateGreeter(Greeter):\n    def greeting(self, name):\n        return f\"Ahoy, {name}!\"\n\n\nfriendly = Greeter()\npirate = PirateGreeter()\nfriendly.greet_all([\"Ada\", \"Linus\"])\npirate.greet_all([\"Ada\", \"Linus\"])\n```\n\n```output\nHello, Ada.\nHello, Linus.\nAhoy, Ada!\nAhoy, Linus!\n```\n\n`greet_all` is written only once, in `Greeter`. When it runs for `pirate`, `self` is the pirate greeter, so `self.greeting(name)` finds the pirate's version. This is a handy way to design classes: the base class does the general work and leaves one small method for each derived class to do in its own way.\n\n### Get the name exactly right\n\nAn overriding method must have exactly the same name as the method it replaces. If you misspell it, Python doesn't complain: it just adds a new method that nobody calls, and the old one keeps running. When an override seems to be ignored, check the spelling first.\n","task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"class Animal:\n    def sound(self):\n        return \"...\"\n\n    def speak(self):\n        return \"It says \" + self.sound()\n\n\nclass Cow(Animal):\n    def sound(self):\n        return \"moo\"\n\n\nclass Fish(Animal):\n    pass\n\n\ndaisy = Cow()\ngoldie = Fish()\nprint(daisy.speak())\nprint(goldie.speak())\nprint(daisy.sound())\n","solution":"class Animal:\n    def sound(self):\n        return \"...\"\n\n    def speak(self):\n        return \"It says \" + self.sound()\n\n\nclass Cow(Animal):\n    def sound(self):\n        return \"moo\"\n\n\nclass Fish(Animal):\n    pass\n\n\ndaisy = Cow()\ngoldie = Fish()\nprint(daisy.speak())\nprint(goldie.speak())\nprint(daisy.sound())\n","hints":["`speak` is only in `Animal`, but it calls `self.sound()`. Which `sound` that is depends on the object.","`daisy` is a `Cow`, and `Cow` overrides `sound`. `Fish` doesn't, so a fish uses the one in `Animal`."],"tests":[{"name":"Output","stdin":"","expect":"It says moo\nIt says ...\nmoo","hidden":false}],"require":[],"forbid":[],"lines":["It says moo","It says ...","moo"],"more":[{"task":"The class `Ticket` works out a ticket's price with the method `final_price`, and its `__str__` uses that method. Write a class `StudentTicket` that inherits `Ticket` and overrides `final_price`: a student ticket costs 5 euros less than the normal price, but never less than 0. For example,\n\n```python\nconcert = StudentTicket(\"Concert\", 25)\nmuseum = StudentTicket(\"Museum\", 4)\nprint(concert)\nprint(museum)\nprint(concert.final_price())\n```\n\nshould print:\n\n```\nConcert: 20 euros\nMuseum: 0 euros\n20\n```\n","kind":"code","seed":"class Ticket:\n    def __init__(self, event, price):\n        self.event = event\n        self.price = price\n\n    def final_price(self):\n        return self.price\n\n    def __str__(self):\n        return f\"{self.event}: {self.final_price()} euros\"\n\n\n# Write the class StudentTicket here.\n\n\nif __name__ == \"__main__\":\n    concert = StudentTicket(\"Concert\", 25)\n    print(concert)\n","solution":"class Ticket:\n    def __init__(self, event, price):\n        self.event = event\n        self.price = price\n\n    def final_price(self):\n        return self.price\n\n    def __str__(self):\n        return f\"{self.event}: {self.final_price()} euros\"\n\n\nclass StudentTicket(Ticket):\n    def final_price(self):\n        if self.price < 5:\n            return 0\n        return self.price - 5\n\n\nif __name__ == \"__main__\":\n    concert = StudentTicket(\"Concert\", 25)\n    print(concert)\n","hints":["`StudentTicket` needs only one method, `final_price(self)`, with the same name as the one it replaces. The constructor and `__str__` are inherited.","Return `self.price - 5`, except when the price is below 5: then return 0.","You don't need a `__str__` of your own: `Ticket`'s `__str__` calls `self.final_price()`, and for a student ticket that's your version."],"tests":[{"name":"Test 1","stdin":"","call":"concert = StudentTicket(\"Concert\", 25)\nmuseum = StudentTicket(\"Museum\", 4)\nprint(concert)\nprint(museum)\nprint(concert.final_price())\n","expect":"Concert: 20 euros\nMuseum: 0 euros\n20","hidden":false},{"name":"Test 2","stdin":"","call":"opera = StudentTicket(\"Opera\", 60)\nzoo = StudentTicket(\"Zoo\", 5)\nnormal = Ticket(\"Opera\", 60)\nprint(opera)\nprint(zoo)\nprint(normal)\n","expect":"Opera: 55 euros\nZoo: 0 euros\nOpera: 60 euros","hidden":true}],"require":[{"pattern":"class\\s+StudentTicket\\s*\\(\\s*Ticket\\s*\\)","message":"`StudentTicket` should inherit `Ticket`: `class StudentTicket(Ticket):`."}],"forbid":[]},{"task":"The class `WordFilter` goes through a list of words in `filter` and keeps the ones that its method `keeps` says yes to. On its own it keeps every word. Write two classes that inherit `WordFilter` and override only `keeps`:\n\n- `ShortWords` keeps the words of at most 4 letters.\n- `LongWords` keeps the words of at least 8 letters.\n\nFor example,\n\n```python\nwords = [\"cat\", \"elephant\", \"dog\", \"giraffe\", \"hippopotamus\"]\nshort = ShortWords()\nlong = LongWords()\nprint(short.filter(words))\nprint(long.filter(words))\n```\n\nshould print:\n\n```\n['cat', 'dog']\n['elephant', 'hippopotamus']\n```\n","kind":"code","seed":"class WordFilter:\n    def keeps(self, word):\n        return True\n\n    def filter(self, words):\n        result = []\n        for word in words:\n            if self.keeps(word):\n                result.append(word)\n        return result\n\n\n# Write the classes ShortWords and LongWords here.\n\n\nif __name__ == \"__main__\":\n    words = [\"cat\", \"elephant\", \"dog\", \"giraffe\", \"hippopotamus\"]\n    short = ShortWords()\n    print(short.filter(words))\n","solution":"class WordFilter:\n    def keeps(self, word):\n        return True\n\n    def filter(self, words):\n        result = []\n        for word in words:\n            if self.keeps(word):\n                result.append(word)\n        return result\n\n\nclass ShortWords(WordFilter):\n    def keeps(self, word):\n        return len(word) <= 4\n\n\nclass LongWords(WordFilter):\n    def keeps(self, word):\n        return len(word) >= 8\n\n\nif __name__ == \"__main__\":\n    words = [\"cat\", \"elephant\", \"dog\", \"giraffe\", \"hippopotamus\"]\n    short = ShortWords()\n    print(short.filter(words))\n","hints":["Each class needs only `keeps(self, word)`, returning `True` for a word it keeps and `False` for the others. `filter` is inherited, and it calls your `keeps`.","A comparison is already `True` or `False`, so `keeps` can return it directly: `return len(word) <= 4`."],"tests":[{"name":"Test 1","stdin":"","call":"words = [\"cat\", \"elephant\", \"dog\", \"giraffe\", \"hippopotamus\"]\nshort = ShortWords()\nlong = LongWords()\nprint(short.filter(words))\nprint(long.filter(words))\n","expect":"['cat', 'dog']\n['elephant', 'hippopotamus']","hidden":false},{"name":"Test 2","stdin":"","call":"words = [\"tree\", \"pinecone\", \"oak\", \"birch\", \"sycamore\", \"elm\", \"evergreen\"]\nprint(ShortWords().filter(words))\nprint(LongWords().filter(words))\nprint(WordFilter().filter(words))\n","expect":"['tree', 'oak', 'elm']\n['pinecone', 'sycamore', 'evergreen']\n['tree', 'pinecone', 'oak', 'birch', 'sycamore', 'elm', 'evergreen']","hidden":true}],"require":[{"pattern":"class\\s+ShortWords\\s*\\(\\s*WordFilter\\s*\\)","message":"`ShortWords` should inherit `WordFilter`."},{"pattern":"class\\s+LongWords\\s*\\(\\s*WordFilter\\s*\\)","message":"`LongWords` should inherit `WordFilter`."},{"pattern":"def\\s+filter\\b","max":1,"message":"Override only `keeps`; the classes inherit `filter` from `WordFilter`."}],"forbid":[]}]}