Правильный способ записи функции __repr__ с наследованием

Я экспериментирую с пионом OOP, и я не был уверен в наследовании функции __repr__. Поскольку функция родительского класса выглядела так:

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

Я хотел знать, лучше ли использовать общий подход (который также подходит для классов детей), например следующий:

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

или если это хорошая практика, чтобы переопределить функцию в каждом классе.

Кроме того, пожалуйста, игнорируйте часть кодировки, так как я оставляю ее.

Ответ 1

Ну, __repr__ имеет особое значение в модели данных Pythons:

object.__repr__(self)

Вызывается встроенной функцией repr() для вычисления "официального" строкового представления объекта. Если это вообще возможно, это должно выглядеть как допустимое выражение Python, которое можно использовать для воссоздания объекта с тем же значением (с учетом соответствующей среды). Если это невозможно, должна быть возвращена строка вида <...some useful description...>. Возвращаемое значение должно быть строковым объектом. Если класс определяет __repr__() но не __str__(), тогда __repr__() также используется, когда требуется "неформальное" строковое представление экземпляров этого класса.

Обычно это используется для отладки, поэтому важно, чтобы представление было насыщенным информацией и однозначным.

Это означает, что строка, возвращаемая __repr__ должна использоваться для создания другого такого же объекта. Так что __repr__ довольно часто нуждается в переопределении не из-за имени __class__.__name__ а из-за того, что "состояние" должно быть зафиксировано в представлении.

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

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

Тогда вам абсолютно необходимо переопределить __repr__ при добавлении параметров для __init__:

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

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

Но в случае, если __repr__ суперкласса все еще точно "описывает" подкласс, тогда нет смысла перегружать __repr__:

class B(A):
     pass

Однако всегда лучше использовать self.__class__.__name__ жесткого кодирования имени класса, на тот случай, если вы или кто-то другой подклассирует его.

Ответ 2

Да - это не просто "хорошо", но это более практично почти в каждой иерархии проектов и классов.

На самом деле, это почти идеальный "пример текстовой книги" того, когда использовать наследование класса, и просто позволить повторному использованию кода в суперклассах.

Ответ 3

Здесь вы можете посмотреть, как я унаследовал метод __repr__ из класса Pesron в классе Student.

Main():

def main():
    person_obj = Person("Jay", "26")  #Instance of Person class
    print(person_obj)
    st_obj = Student("Jenny", "24", "12345") #Instance of Student class
    print(st_obj)

Базовый класс: Лицо

class Person:
    name = ""  
    age = 0  

    def __init__(self, personName, personAge):  
        self.name = personName  
        self.age = personAge  

    def __repr__(self):
        return "Hello.. greeting!! {} {} ".format(self.name, self.age) 

Производный класс: Студент

class Student(Person):
    studentId = ""  

def __init__(self, studentName, studentAge, studentId):  
    Person.__init__(self, studentName, studentAge)  
    self.studentId = studentId  

def __repr__(self):
    return super().__repr__() + " id is:  {} ".format(self.studentId)


if __name__ == '__main__':
    main()