Correct way to write __repr__ function with inheritance
Asked Answered
B

2

25

I'm experimenting with OOP python and I wasn't sure about the __repr__ function inheritance. Since the parent class function looked like this:

def __repr__(self):
    '''Returns representation of the object'''
    return("{}({!r})".format("Class name", self._param))

I wanted to know if it is better to use a generic approach (which could be suitable for children classes as well) like the following one:

def __repr__(self):
    '''Returns representation of the object'''
    return("{}({!r})".format(self.__class__.__name__, self._param))

or if it is a good practice to override the function in every class.

Also, please ignore the encoding part, since I'm leaving it behind.

Belittle answered 3/6, 2017 at 8:43 Comment(2)
Generally speaking, it's fine to override the method if you want don't want to extend it.Birdella
If all the child classes have the _param attribute, then it's quite safe for them to inherit that __repr__ from the parent class.Deena
S
19

Well the __repr__ has a special meaning in Pythons data model:

object.__repr__(self)

Called by the repr() built-in function to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment). If this is not possible, a string of the form <...some useful description...> should be returned. The return value must be a string object. If a class defines __repr__() but not __str__(), then __repr__() is also used when an “informal” string representation of instances of that class is required.

This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.

That means the string that is returned by __repr__ should be usable to create another object just like it. So __repr__ is something that quite often needs overriding, not because of the __class__.__name__ but because the "state" has to be captured in the representation.

class A(object):
    def __init__(self, param):
        self._param = param

    def __repr__(self):
        '''Returns representation of the object'''
        return("{}({!r})".format(self.__class__.__name__, self._param))

Then you absolutely should override the __repr__ when you add parameters for __init__:

class B(A):
    def __init__(self, param1, param2):
        self._param = param1
        self._param2 = param2

    def __repr__(self):
        '''Returns representation of the object'''
        return("{}({!r})".format(self.__class__.__name__, self._param, self._param2))

But in case the __repr__ of the superclass still accurately "describes" the subclass then there's no point overloading the __repr__:

class B(A):
     pass

However it's always a good choice to use self.__class__.__name__ over hard-coding the class name, just in case you or someone else subclasses it.

Senzer answered 3/6, 2017 at 9:34 Comment(3)
You should take the ability for recreating an object from its repr recomendtion with a grain of salt: it is great for some kindof objects, still it was thought up at a time when Pyhton's input would call "eval" on the value typed by the user: it was another mindset for interactive use of the Python language. Depending on the kind of object it is not really practical - and sometimes not even desirable - taht repr works this way.Dispassion
@Dispassion It's more important for debugging (and when you post on StackOverflow). When the representation contains all necessary informations that define the instance then it's much easier to recreate a particular state or "see" what is going on.Senzer
I think type(self).__name__ is a better choice for __repr__ since it gives the real class name of self—that is what you want when you debug with repr—which might be different from its virtual class name, usually for proxy objects, such as those returned by weakref.proxy (cf. my answer).Mollie
D
3

Yes - - it is not just "ok", but it is what is more practical in almost every project and class hierarchy.

Actually, this is almost a perfect "text book example" of when to use class inheritance, and just let the code in the superclasses be reused.

Dispassion answered 3/6, 2017 at 9:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.