7.3. Operator String Repr

  • Typing obj into REPL (console) calls repr(obj)

  • Calling repr(obj) calls obj.__repr__()

  • Method obj.__repr__() must return str

  • Intended for developers of your class

  • Shows object representation

  • Copy-paste for creating object with the same values

  • Useful for debugging

  • Printing list will call __repr__() method on each element

7.3.1. Inherited

Object without __repr__() method overloaded prints their memory address:

>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
>>>
>>>
>>> mark = User('Mark', 'Watney')
>>>
>>> mark  
<__main__.User object at 0x...>
>>>
>>> repr(mark)  
'<__main__.User object at 0x...>'
>>>
>>> mark.__repr__()  
'<__main__.User object at 0x...>'

7.3.2. Overloaded

>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __repr__(self):
...         clsname = self.__class__.__name__
...         firstname = self.firstname
...         lastname = self.lastname
...         return f'{clsname}({firstname=}, {lastname=})'
>>>
>>>
>>> mark = User('Mark', 'Watney')
>>>
>>> mark
User(firstname='Mark', lastname='Watney')
>>>
>>> repr(mark)
"User(firstname='Mark', lastname='Watney')"
>>>
>>> mark.__repr__()
"User(firstname='Mark', lastname='Watney')"

7.3.3. Nested

  • Printing list will call __repr__() method on each element

>>> data = [1,2,3]
>>> print(data)
[1, 2, 3]
>>> class MyClass:
...     def __repr__(self): return 'repr'
...     def __str__(self): return 'str'
>>>
>>> data = [
...     MyClass(),
...     MyClass(),
...     MyClass(),
... ]
>>>
>>>
>>> print(data)
[repr, repr, repr]
>>>
>>> data
[repr, repr, repr]
>>>
>>> str(data)
'[repr, repr, repr]'
>>>
>>> repr(data)
'[repr, repr, repr]'

7.3.4. Use Case - 0x01

Printing list will call __repr__() method on each element:

>>> class User:
...     def __init__(self, firstname, lastname):
...         self.firstname = firstname
...         self.lastname = lastname
...
...     def __repr__(self):
...         return f'{self.firstname} {self.lastname}'
>>>
>>> admins = [
...     User('Mark', 'Watney'),
...     User('Melissa', 'Lewis'),
...     User('Rick', 'Martinez'),
... ]
>>>
>>> print(admins)
[Mark Watney, Melissa Lewis, Rick Martinez]

7.3.5. Assignments

Code 7.22. Solution
"""
* Assignment: Operator String Repr
* Type: class assignment
* Complexity: easy
* Lines of code: 3 lines
* Time: 3 min

English:
    1. Overload `repr()`
    2. Run doctests - all must succeed

Polish:
    1. Przeciąż `repr()`
    2. Uruchom doctesty - wszystkie muszą się powieść

Tests:
    >>> import sys; sys.tracebacklimit = 0
    >>> from inspect import isclass, ismethod

    >>> assert isclass(Iris)
    >>> iris = Iris(DATA)

    >>> assert hasattr(Iris, '__repr__')
    >>> assert ismethod(iris.__repr__)
    >>> repr(iris)
    "Iris(features=[4.7, 3.2, 1.3, 0.2], label='setosa')"
"""

DATA = (4.7, 3.2, 1.3, 0.2, 'setosa')

# repr() -> Iris(features=[4.7, 3.2, 1.3, 0.2], label='setosa')
class Iris:
    features: list
    label: str

    def __init__(self, data):
        self.features = list(data[:-1])
        self.label = str(data[-1])


Code 7.23. Solution
"""
* Assignment: Operator String Nested
* Type: class assignment
* Complexity: medium
* Lines of code: 9 lines
* Time: 13 min

English:
    1. Overload `str` and `repr` to achieve desired printing output
    2. Run doctests - all must succeed

Polish:
    1. Przeciąż `str` i `repr` aby osiągnąć oczekiwany rezultat wypisywania
    2. Uruchom doctesty - wszystkie muszą się powieść

Hints:
    * Define `Accounts.__str__()`
    * Define `User.__str__()` and `User.__repr__()`
    * Define `Group.__repr__()`
    * Printing list will call repr on all elements

Tests:
    >>> import sys; sys.tracebacklimit = 0

    >>> result = User('Rick', 'Martinez')
    >>> print(result)
    Rick Martinez

    >>> result = User('Mark', 'Watney', groups=[
    ...     Group(gid=2, name='staff'),
    ... ])
    >>> print(result)
    Mark Watney member of [gid=2(staff)]

    >>> result = User('Melissa', 'Lewis', groups=[
    ...     Group(gid=1, name='admins'),
    ...     Group(gid=2, name='staff'),
    ... ])
    >>> print(result)
    Melissa Lewis member of [gid=1(admins), gid=2(staff)]

    >>> result = Accounts([
    ...     User('Mark', 'Watney', groups=[
    ...         Group(gid=2, name='staff'),
    ...     ]),
    ...     User('Melissa', 'Lewis', groups=[
    ...         Group(gid=1, name='admins'),
    ...         Group(gid=2, name='staff'),
    ...     ]),
    ...     User('Rick', 'Martinez'),
    ... ])
    >>>
    >>> print(result)  # doctest: +NORMALIZE_WHITESPACE
    Mark Watney member of [gid=2(staff)]
    Melissa Lewis member of [gid=1(admins), gid=2(staff)]
    Rick Martinez
"""


class Accounts:
    def __init__(self, users):
        self.users = users


class User:
    def __init__(self, firstname, lastname, groups=None):
        self.firstname = firstname
        self.lastname = lastname
        self.groups = groups if groups else []


class Group:
    def __init__(self, gid, name):
        self.gid = gid
        self.name = name