{"id":"class-examples-str","slug":"printing-objects","title":"Printing an object with __str__","text":"When you print an object of your own class, Python doesn't know which of its data matters, so it prints the class's name and the object's address in memory, something like this:\n\n```text\n<__main__.Match object at 0x7f8e2a4b3d10>\n```\n\nThat's no use to anyone, and the address changes on every run. A class can say how its objects should be shown by having a method called `__str__`. It returns a string that describes the object's state, and `print` uses it:\n\n```python\nclass Match:\n    def __init__(self, home, away):\n        self.home = home\n        self.away = away\n        self.home_goals = 0\n        self.away_goals = 0\n\n    def goal(self, team):\n        if team == self.home:\n            self.home_goals += 1\n        else:\n            self.away_goals += 1\n\n    def __str__(self):\n        return f\"{self.home} {self.home_goals}-{self.away_goals} {self.away}\"\n\n\nfinal = Match(\"Lions\", \"Tigers\")\nprint(final)\nfinal.goal(\"Lions\")\nfinal.goal(\"Tigers\")\nfinal.goal(\"Lions\")\nprint(final)\n```\n\n```output\nLions 0-0 Tigers\nLions 2-1 Tigers\n```\n\n`__str__` has two underscores on each side, like `__init__`. Methods with names like these are **special methods**: you don't call them yourself, Python calls them when it needs them. It calls `__init__` when an object is made, and `__str__` whenever the object has to be turned into a string. That happens in `print`, in the function `str` and in f-strings:\n\n```python\nclass Match:\n    def __init__(self, home, away):\n        self.home = home\n        self.away = away\n        self.home_goals = 3\n        self.away_goals = 3\n\n    def __str__(self):\n        return f\"{self.home} {self.home_goals}-{self.away_goals} {self.away}\"\n\n\ncup = Match(\"Owls\", \"Foxes\")\ntext = str(cup)\nprint(len(text))\nprint(f\"Full time: {cup}\")\n```\n\n```output\n14\nFull time: Owls 3-3 Foxes\n```\n\n### Return the string, don't print it\n\n`__str__` must **return** a string. A common mistake is to print it inside the method instead. The method then returns `None`, and Python stops:\n\n```python\nclass Match:\n    def __init__(self, home, away):\n        self.home = home\n        self.away = away\n\n    def __str__(self):\n        print(f\"{self.home} vs {self.away}\")\n\n\ngame = Match(\"Owls\", \"Foxes\")\nprint(game)\n```\n\n```output\nOwls vs Foxes\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 11, in <module>\n    print(game)\n    ~~~~~^^^^^^\nTypeError: __str__ returned non-string (type NoneType)\n```\n\nThe line was printed by the `print` inside `__str__`, and then `print(game)` got `None` back instead of a string.\n\nOne more thing: printing a whole list of objects, such as `print([final, cup])`, still shows the addresses, because a list shows its items in another way. Print the objects one at a time in a loop instead.\n","task":"Fill in the blanks, so that the class has a `__str__` method and the program prints:\n\n```\nBolt (battery 80%)\n```\n","kind":"fill","seed":"class Robot:\n    def __init__(self, name, battery):\n        self.name = name\n        self.battery = battery\n\n    def [[__str__]](self):\n        [[return]] f\"{self.name} (battery {self.battery}%)\"\n\n\nhelper = Robot(\"Bolt\", 80)\nprint(helper)\n","solution":"class Robot:\n    def __init__(self, name, battery):\n        self.name = name\n        self.battery = battery\n\n    def __str__(self):\n        return f\"{self.name} (battery {self.battery}%)\"\n\n\nhelper = Robot(\"Bolt\", 80)\nprint(helper)\n","hints":["The method that `print` uses has two underscores on each side of its name.","The method is `__str__`, and it hands the string back with `return`."],"tests":[{"name":"Output","stdin":"","expect":"Bolt (battery 80%)","hidden":false}],"require":[],"forbid":[],"more":[{"task":"This program should print the two lines below, but it stops with an error. Fix the `__str__` method.\n\n```\nMovie night: Up (2009)\nUp (2009)\n```\n","kind":"code","seed":"class Movie:\n    def __init__(self, title, year):\n        self.title = title\n        self.year = year\n\n    def __str__(self):\n        print(f\"{self.title} ({self.year})\")\n\n\nfilm = Movie(\"Up\", 2009)\nprint(f\"Movie night: {film}\")\nprint(film)\n","solution":"class Movie:\n    def __init__(self, title, year):\n        self.title = title\n        self.year = year\n\n    def __str__(self):\n        return f\"{self.title} ({self.year})\"\n\n\nfilm = Movie(\"Up\", 2009)\nprint(f\"Movie night: {film}\")\nprint(film)\n","hints":["Read the error: `__str__` returned `None`, not a string.","`__str__` must hand the string back with `return`, not print it."],"tests":[{"name":"Output","stdin":"","expect":"Movie night: Up (2009)\nUp (2009)","hidden":false}],"require":[],"forbid":[]},{"task":"Write a class `Parcel` whose constructor takes the receiver's name and the weight in kilograms, and stores them in the attributes `receiver` and `kg`. Every new parcel also has the attribute `delivered`, set to `False`. Give it a method `deliver()`, which marks the parcel delivered, and a `__str__` method that returns the text shown below: when the parcel has been delivered, it ends with ` (delivered)`.\n\nThis code:\n\n```python\nbox = Parcel(\"Ada\", 2.5)\nprint(box)\nbox.deliver()\nprint(box)\n```\n\nprints\n\n```\nParcel for Ada, 2.5 kg\nParcel for Ada, 2.5 kg (delivered)\n```\n","kind":"code","seed":"# Write the class Parcel here.\n\n\nif __name__ == \"__main__\":\n    box = Parcel(\"Ada\", 2.5)\n    print(box)\n","solution":"class Parcel:\n    def __init__(self, receiver, kg):\n        self.receiver = receiver\n        self.kg = kg\n        self.delivered = False\n\n    def deliver(self):\n        self.delivered = True\n\n    def __str__(self):\n        text = f\"Parcel for {self.receiver}, {self.kg} kg\"\n        if self.delivered:\n            text += \" (delivered)\"\n        return text\n\n\nif __name__ == \"__main__\":\n    box = Parcel(\"Ada\", 2.5)\n    print(box)\n","hints":["`deliver` only sets `self.delivered = True`.","In `__str__`, build the text with an f-string, and add `\" (delivered)\"` to it when `self.delivered` is `True`.","Return the finished string at the end of `__str__`."],"tests":[{"name":"Test 1","stdin":"","call":"box = Parcel(\"Ada\", 2.5)\nprint(box)\nbox.deliver()\nprint(box)\n","expect":"Parcel for Ada, 2.5 kg\nParcel for Ada, 2.5 kg (delivered)","hidden":false},{"name":"Test 2","stdin":"","call":"big = Parcel(\"Grace Hopper\", 14)\nsmall = Parcel(\"Linus\", 0.3)\nsmall.deliver()\nprint(big)\nprint(small)\nprint(str(big).upper())\n","expect":"Parcel for Grace Hopper, 14 kg\nParcel for Linus, 0.3 kg (delivered)\nPARCEL FOR GRACE HOPPER, 14 KG","hidden":true}],"require":[],"forbid":[]}]}