Возможно ли создавать атрибуты вложенного класса?

#python #python-3.x #class

#python #python-3.x #класс

Вопрос:

Я довольно новичок в Python и недавно узнал о классах. Я экспериментировал с ними и придумал систему оценки студентов / курсов. Вот код до сих пор:

 class course:
    TOTAL_COURSES = 0

    def __init__(self, name, room, max_students):
        self.name = name
        self.room = room
        self.max_students = max_students
        self.student_list = []
        course.TOTAL_COURSES  = 1
 
    def addStudent(self, student):
        # Checks if the class is below max capacity
        if len(self.student_list) < self.max_students:
            self.student_list.append(student)
            # Adds the course to the student's course list
            student.course_list.append(self)
            return True
        return False
 

Таким образом, создается класс курса, в который я могу добавлять учеников и устанавливать их комнаты и другие вещи. У меня есть другой класс, который предназначен для хранения информации о студентах:

 class student:
    TOTAL_STUDENTS = 0

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        # Courses in course_list are stored as objects
        self.course_list = []
        student.TOTAL_STUDENTS  = 1
 

Довольно просто; Я только что зациклился на том, как создать реальную систему оценивания. Если бы я должен был сделать:

 s1 = student("Tom", 17, "Male")
c1 = course("English", "E123", 25)
 

Можно ли затем использовать «вложенные атрибуты»? Поэтому я бы присвоил этому ученику оценку курса такому значению, как:

 s1.c1.grade = "A "
 

Однако это не работает и выдает (ожидаемый) Ошибка атрибута. Так должен ли я использовать мой ранее созданный course_list?

 s1.course_list[0].grade = "A "
 

Даже тогда я не уверен, как бы я назначил оценку этому объекту курса.

Комментарии:

1. Если бы вы попытались, вы бы знали, что s1.c1.grade это неправильно.

2. Я знаю, я пытаюсь понять, есть ли способ отформатировать его таким образом.

3. Элементы ваших классов не имеют отступов.

4. Вы могли бы сделать что-то подобное, вложив Bunch объекты. Смотрите sklearn.utils.Bunch документацию. Исходный код Bunch довольно короткий.

5. Отредактировано для устранения ошибок отступов, по какой-либо причине оно не было перенесено из IDE в post.

Ответ №1:

Вот решение, которое устраняет некоторые из вышеупомянутых проблем, назначая «слот курса» учащемуся, а не самому курсу. Как вы можете себе представить, существует ограничение на количество доступных слотов курса, которое зависит от максимального размера курса. Код можно доработать намного дальше, но я подумал, что это может быть полезно для начала:

 class Student:

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        self.courses = {}
        
    def addCourse(self, course):
        if course.status=='Enrolled':
            self.courses[course.name] = course
        else:
            self.courses[course.name] = course.status

            
class Course:

    def __init__(self, name, room, max_students):
        self.name = name
        self.room = room
        self.max_students = max_students
        self.student_list = []
        
        self.course_slots_filled = 0
        self.course_slots_available = max_students
        
    def __str__(self):
        return 'Course_object_{}'.format(self.name)
 
    def check_slots_available(self):
        if self.course_slots_filled < self.max_students:
            return True
        else:
            return False
    
    class CourseSlot:
        def __init__(self, name, student_name, status):
            self.name = name
            self.student_name = student_name
            self.status = status
            self.grade = 'No grade assigned'
        
        def __repr__(self):
            return 'CourseSlot_object_{}'.format(self.name)
        
        def set_grade(self, grade):
            self.grade = grade
            
    
    def assign_course_slot(self, student_name):
        if self.check_slots_available():
            self.course_slots_filled =1
            self.course_slots_available-=1
            status = 'Enrolled'
            self.student_list.append(student_name)
        else:
            print('Sorry, {} class is full! {} not enrolled.'.format(self.name, student_name))
            status = 'Not enrolled'
            
        return self.CourseSlot(self.name, student_name, status)
 

Пример использования

Создание экземпляров курсов:

 physics = Course('Physics','101',5)
chemistry = Course('Chemistry','102',1)
 

Создайте экземпляр student 1 и назначьте слот для курса:

 s1 = Student("Tom", 17, "Male")
s1.addCourse(physics.assign_course_slot(s1.name))
s1.addCourse(chemistry.assign_course_slot(s1.name))
s1.courses['Physics'].set_grade('A ')

[v for v in s1.courses.values()]

# >>> [CourseSlot_object_Physics, CourseSlot_object_Chemistry]
 

Создайте экземпляр student 2 и назначьте слот для курса

 s2 = Student("Susan", 18, "Female")
s2.addCourse(physics.assign_course_slot(s2.name))
s2.addCourse(chemistry.assign_course_slot(s2.name))

#>>> Sorry, Chemistry class is full! Susan not enrolled.
 

Получить информацию о курсе:

 print('Physics course slots filled: ',physics.course_slots_filled)
print('Physics course slots available: ',physics.course_slots_available)
print('Chemistry course slots filled: ',chemistry.course_slots_filled)
print('Chemistry course slots available: ',chemistry.course_slots_available)

#>>> Physics course slots filled:  2
#    Physics course slots available:  3
#    Chemistry course slots filled:  1
#    Chemistry course slots available:  0

print('Physics student list: ',physics.student_list)
print('Chemistry student list: ',chemistry.student_list)

# >>> Physics student list:  ['Tom', 'Susan']
#     Chemistry student list:  ['Tom']

for s in [s1,s2]:
    for c in s.courses.values():
        try:
            print('{} {} grade: {}'.format(s.name, c.name, c.grade))
        except AttributeError:
            pass

# >>> Tom Physics grade: A 
#     Tom Chemistry grade: No grade assigned
#     Susan Physics grade: No grade assigned
 

Я предполагаю, что обман заключается в том, что курс student_list получает только имя студента, а не объект Student, что, вероятно, может сработать, если вы передадите ему уникальный идентификатор, а затем выполните итерацию по списку объектов Student для сопоставления по ID. В любом случае есть о чем подумать.

Ответ №2:

Класс присваивается комбинации a student и course объекта, поэтому он не может быть отдельным атрибутом ни одного из них.

Я бы счел оценки более близкими к студентам, чем к курсам, поэтому я бы добавил словарь student с уникальным идентификатором курса (например, его именем) в качестве ключа и оценкой в качестве значения. Далее вам, вероятно, понадобится функция для выбора курса с заданным идентификатором (именем) из вашего списка курсов.

Для дальнейшего улучшения вашего кода вы можете создать course хешируемый класс, который представляет собой класс с __hash__ методом (посмотрите это в документации Python). Тогда вы можете использовать course объекты непосредственно в качестве ключей словаря вместо работы с идентификаторами.