Repository navigation
Expand file tree
/
Copy pathcourse.py
More file actions
176 lines (141 loc) · 6.02 KB
/
Copy pathcourse.py
File metadata and controls
176 lines (141 loc) · 6.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
"""CSC148 Assignment 1
=== CSC148 Winter 2023 ===
Department of Computer Science,
University of Toronto
This code is provided solely for the personal and private use of
students taking the CSC148 course at the University of Toronto.
Copying for purposes other than this use is expressly prohibited.
All forms of distribution of this code, whether as given or with
any changes, are expressly prohibited.
Authors: Misha Schwartz, Mario Badr, Christine Murad, Diane Horton,
Sophia Huynh, Jaisie Sin, Tom Ginsberg, Jonathan Calver, and Jacqueline Smith
All of the files in this directory and all subdirectories are:
Copyright (c) 2023 Misha Schwartz, Mario Badr, Diane Horton, Sophia Huynh,
Jonathan Calver, and Jacqueline Smith
=== Module Description ===
This file contains classes that describe a university course and the students
who are enrolled in these courses.
"""
from __future__ import annotations
from typing import Dict, TYPE_CHECKING, Optional
if TYPE_CHECKING:
from survey import Answer, Survey, Question
# Provided helper function
def sort_students(lst: list[Student], attribute: str) -> list[Student]:
"""Return a shallow copy of <lst> sorted by <attribute> in non-decreasing
order.
Being a shallow copy means that a new list is returned, but it contains
ids of the same Student objects as in <lst>; no new Student objects are
created. The conseqence of this is that aliasing exists. Suggestion: draw
a memory model diagram to ensure that you understand this.
Preconditions:
- <attribute> is an attribute name for the Student class
>>> s1 = Student(1, 'Misha')
>>> s2 = Student(2, 'Diane')
>>> s3 = Student(3, 'Mario')
>>> sort_students([s1, s3, s2], 'id') == [s1, s2, s3]
True
>>> sort_students([s1, s2, s3], 'name') == [s2, s3, s1]
True
"""
return sorted(lst, key=lambda student: getattr(student, attribute))
class Student:
"""A Student who can be enrolled in a university course.
=== Public Attributes ===
id: the id of the student
name: the name of the student
=== Private Attributes ===
_question_answer: the dict that keeps Question as key and answer as values.
=== Representation Invariants ===
name is not the empty string
"""
id: int
name: str
_question_answer: Dict[int, Answer]
def __init__(self, id_: int, name: str) -> None:
"""Initialize a student with name <name> and id <id>"""
self.id = id_
self.name = name
self._question_answer = {}
def __str__(self) -> str:
"""Return the name of this student """
return self.name
def has_answer(self, question: Question) -> bool:
"""Return True iff this student has an answer for a question with the
same id as <question> and that answer is a valid answer for <question>.
"""
for in_question in self._question_answer:
if in_question == question.id and \
self._question_answer[in_question] is not None:
answer = self._question_answer[in_question]
if answer.is_valid(question):
return True
return False
def set_answer(self, question: Question, answer: Answer) -> None:
"""Record this student's answer <answer> to the question <question>.
If this student already has an answer recorded for the question, then
replace it with <answer>.
"""
self._question_answer[question.id] = answer
def get_answer(self, question: Question) -> Optional[Answer]:
"""Return this student's answer to the question <question>.
Return None if this student does not have an answer to <question>
"""
if question.id not in self._question_answer:
return None
return self._question_answer[question.id]
class Course:
"""A University Course
=== Public Attributes ===
name: the name of the course
students: a list of students enrolled in the course
=== Private Attributes ===
=== Representation Invariants ===
- No two students in this course have the same id
- name is not the empty string
"""
name: str
students: list[Student]
def __init__(self, name: str) -> None:
"""Initialize a course with the name of <name>.
"""
self.name = name
self.students = []
def enroll_students(self, students: list[Student]) -> None:
"""Enroll all students in <students> in this course.
If adding any student would violate a representation invariant,
do not add any of the students in <students> to the course.
"""
duplicated_id = False
for i in range(len(students)):
for k in range(i + 1, len(students)):
if students[i].id == students[k].id:
duplicated_id = True
for student in self.students:
for other in students:
if student.id == other.id:
duplicated_id = True
if self.name != '' and duplicated_id is not True:
for student in students:
self.students.append(student)
def all_answered(self, survey: Survey) -> bool:
"""Return True iff all the students enrolled in this course have a
valid answer for every question in <survey>.
"""
for question in survey.get_questions():
for student in self.get_students():
if not student.has_answer(question):
return False
return True
def get_students(self) -> tuple[Student]:
"""Return a tuple of all students enrolled in this course.
The students in this tuple should be in order according to their id
from the lowest id to the highest id.
Hint: the sort_students function might be useful
"""
student_tuple = tuple(sort_students(self.students, 'id'))
return student_tuple
if __name__ == '__main__':
import python_ta
python_ta.check_all(config={'extra-imports': ['typing', 'survey'],
'disable': ['E9992']})