Как добраться до переменной в магическом методе

Есть такой вот студент

class Student:
    def __init__(self, name, surname, gender):
        self.name = name
        self.surname = surname
        self.gender = gender
        self.finished_courses = []
        self.courses_in_progress = []
        self.grades = {}

    def __str__(self):
        average_grade = sum(elem for num in self.grades.values() for elem in num) / len(
            [elem for num in self.grades.values() for elem in num])
        return f'''Имя: {self.name}
Фамилия: {self.surname}
Средняя оценка за домашние задания: {average_grade}
Курсы в процессе изучения: {self.courses_in_progress}
Завершенные курсы: {self.finished_courses}'''

Мне нужна его переменная average_grade чтобы сравнивать студентов по средней оценке. Но если ставить ее в __init__ начинает ругаться на division by zero. Может есть способ достать ее из __str__?


Ответы (2 шт):

Автор решения: insolor

Можно добавить метод для вычисления средней оценки:

class Student:
    def __init__(self, name, surname, gender):
        self.name = name
        self.surname = surname
        self.gender = gender
        self.finished_courses = []
        self.courses_in_progress = []
        self.grades = {}

    def get_average_grade(self):
        return sum(elem for num in self.grades.values() for elem in num) / len(
            [elem for num in self.grades.values() for elem in num])

    def __str__(self):
        return f'''Имя: {self.name}
Фамилия: {self.surname}
Средняя оценка за домашние задания: {self.get_average_grade()}
Курсы в процессе изучения: {self.courses_in_progress}
Завершенные курсы: {self.finished_courses}'''

Потом вызываете его где вам нужно.

Либо делаете вычисляемое поле - тот же самый метод, но с декоратором @property. Обращение к нему как будто это обычное поле:

class Student:
    def __init__(self, name, surname, gender):
        self.name = name
        self.surname = surname
        self.gender = gender
        self.finished_courses = []
        self.courses_in_progress = []
        self.grades = {}

    @property
    def average_grade(self):
        return sum(elem for num in self.grades.values() for elem in num) / len(
            [elem for num in self.grades.values() for elem in num])

    def __str__(self):
        return f'''Имя: {self.name}
Фамилия: {self.surname}
Средняя оценка за домашние задания: {self.average_grade}
Курсы в процессе изучения: {self.courses_in_progress}
Завершенные курсы: {self.finished_courses}'''

Выражение elem for num in self.grades.values() for elem in num лучше вынести в отдельную переменную, вычислить один раз, потом делить его сумму на его длину:

    @property
    def average_grade(self):
        grades = [elem for num in self.grades.values() for elem in num]
        return sum(grades) / len(grades)
→ Ссылка
Автор решения: DGDays

Как вариант сделать инициализировать привптную переменную, которой будет присваиваться значение и через специальный метод она будет возвращаться

Пример:

class Student:
    def __init__(self, name, surname, gender):
        self.name = name
        self.surname = surname
        self.gender = gender
        self.finished_courses = []
        self.courses_in_progress = []
        self.grades = {}
        self.__average_grade = None

    def aver(self):
        return self.__average_grade
    def __str__(self):
        average_grade = sum(elem for num in self.grades.values() for elem in num) / len(
            [elem for num in self.grades.values() for elem in num])
        self._average_grade = average_grade
        return f'''Имя: {self.name}
Фамилия: {self.surname}
Средняя оценка за домашние задания: {average_grade}
Курсы в процессе изучения: {self.courses_in_progress}
Завершенные курсы: {self.finished_courses}'''

st = Student('Евгений', 'Малевичев', 'Male')
print(st.aver())
→ Ссылка