Python Programming from First Principles: Learn to Code, Think Computationally, and Solve Real-World Problems
PDFEPUB
BOOK 000 · CHAPTER 7 · From Diagram to Code

From Diagram to Code

On this pageDefine the ModelCreate the Object Snapshot

Translate the model one responsibility at a time: fields become instance attributes; operations become methods; associations become references to other objects.

The UML activity diagram shows the translation workflow; rounded boxes are actions read from the start circle to the end bullseye.

Read the Student, Course and Enrollment class modelImplement attributes, operations and references in PythonCreate ada, cs101 and enr1Compare their values and links with the object diagram

Define the Model

None means no grade has been assigned. A list comprehension builds a new list by reading the enrollment links. raise ValueError(...) rejects an input that breaks a model rule.

class Student:
    def __init__(self, student_id, name):
        self.student_id = student_id
        self.name = name
        self._enrollments = []

    def enroll(self, course):
        for enrollment in self._enrollments:
            if enrollment.course is course:
                raise ValueError("Already enrolled")
        enrollment = Enrollment(self, course)
        self._enrollments.append(enrollment)
        course._enrollments.append(enrollment)
        return enrollment

    def course_codes(self):
        return [enrollment.course.course_code for enrollment in self._enrollments]


class Course:
    def __init__(self, course_code, title, credits):
        if not isinstance(credits, int) or isinstance(credits, bool) or credits <= 0:
            raise ValueError("Credits must be a positive integer")
        self.course_code = course_code
        self.title = title
        self.credits = credits
        self._enrollments = []

    def student_names(self):
        return [enrollment.student.name for enrollment in self._enrollments]


class Enrollment:
    def __init__(self, student, course):
        self.student = student
        self.course = course
        self._grade = None

    @property
    def grade(self):
        return self._grade

    def set_grade(self, value):
        if value not in {"A", "B", "C", "D", "F"}:
            raise ValueError("Grade must be A, B, C, D or F")
        self._grade = value
Listing 346 — Define the Model

The definitions produce no visible output. Use Student.enroll to create and register a link on both sides; directly constructing Enrollment would not register it.

Create the Object Snapshot

Continue with all three class definitions above:

ada = Student("S001", "Ada Lovelace")
cs101 = Course("CS101", "Intro to CS", 6)
enr1 = ada.enroll(cs101)
enr1.set_grade("A")
print(ada.course_codes())
print(cs101.student_names())
print(enr1.grade)
Listing 347 — Create the Object Snapshot

Output

['CS101']
['Ada Lovelace']
A

The returned enrollment links Ada and CS101; its grade becomes A. Each query builds a new list from those links.

Keep one Course object per catalog code: duplicate detection here uses object identity. Data is held only in memory.

Try it: enroll Grace in CS101, grade her enrollment B, and check that Ada’s grade remains A. Then reject grade Z and confirm that the stored grade is unchanged.

The model now supports enrollment and grading. Application design begins by asking who uses these operations and what they want to achieve.