from datetime import date

def calculate_age(born):
    today = date.today()
    return today.year - born.year - ((today.month, today.day) < (born.month, born.day))

dob = date(2004, 12, 31)
age = calculate_age(dob)
print(age)
18
import json

class Student:    

    def __init__(self, name, car, price, rating):
        self._name = name    # variables with self prefix become part of the object, 
        self._car = car
        self._price = price
        self._rating = rating
    
    @property
    def name(self):
        return self._name
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def name(self):
        self._name = name
    
    # a getter method, extracts email from object
    @property
    def price(self):
        return self._price
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def price(self):
        self._car = car
        
    
    # dob property is returned as string, to avoid unfriendly outcomes
    @property
    def price(self):
        return self._price
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def price(self):
        self._price = price
        
    # age is calculated and returned each time it is accessed
    @property
    def car(self):
        return self._car
    
    # a setter function, allows name to be updated after initial object creation
    @name.setter
    def rating(self):
        self._rating = rating
    
    # dictionary is customized, removing password for security purposes
    @property
    def dictionary(self):
        dict = {
            "name" : self.name,
            "car" : self.car,
            "price" : self.price,
            "rating" : self.rating
        }
        return dict
    

   
    
    # output content using json dumps, this is ready for API response
    def __str__(self):
        return json.dumps(self.dictionary)
    
    # output command to recreate the object, uses attribute directly
    def __repr__(self):
        return f'Student(name={self._name}, car={self._car}, price={self._price},rating={self._rating})'
    

Student1 = Student("Dillon", "Honda Civic", 27000, 9)
Student2 = Student("Adi", "Tesla Model Y", 66000, 10)
print("Student 1 is named ", Student1.name)
print("Student 1 owns a ", Student1.car)
print("Student 1's car costed ", Student1.price)
print("Student 1 rates their car a ", Student1.rating)
print("Student 2 is named ", Student2.name)
print("Student 2 owns a ", Student2.car)
print("Student 2's car costed ", Student2.price)
print("Student 2 rates their car a ", Student2.rating)

print(Student1)
print(Student2)
Student 1 is named  Dillon
Student 1 owns a  Honda Civic
Student 1's car costed  Dillon
Student 1 rates their car a  Dillon
Student 2 is named  Adi
Student 2 owns a  Tesla Model Y
Student 2's car costed  Adi
Student 2 rates their car a  Adi
{"name": "Dillon", "car": "Honda Civic", "price": "Dillon", "rating": "Dillon"}
{"name": "Adi", "car": "Tesla Model Y", "price": "Adi", "rating": "Adi"}

complications

Undesired output at the bottom with:

{"name": "Dillon", "car": "Honda Civic", "price": "Dillon", "rating": "Dillon"} {"name": "Adi", "car": "Tesla Model Y", "price": "Adi", "rating": "Adi"}

price and rating incorrect

took a while but fixed it below

import json

class Student:    

    def __init__(self, name, car, price, rating):
        self._name = name
        self._car = car
        self._price = price
        self._rating = rating
    
    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self, name):
        self._name = name
    
    @property
    def price_property(self):
        return self._price
    
    @price_property.setter
    def price(self, price):
        self._price = price
        
    @property
    def car(self):
        return self._car
    
    @car.setter
    def car(self, car):
        self._car = car
        
    @property
    def rating_property(self):
        return self._rating
    
    @rating_property.setter
    def rating(self, rating):
        self._rating = rating
    
    @property
    def dictionary(self):
        dict = {
            "name" : self.name,
            "car" : self.car,
            "price" : self.price,
            "rating" : self.rating
        }
        return dict
    
    def __str__(self):
        return json.dumps(self.dictionary)
    
    def __repr__(self):
        return f'Student(name={self._name}, car={self._car}, price={self._price},rating={self._rating})'
    

Student1 = Student("Dillon", "Honda Civic", 27000, 9)
Student2 = Student("Adi", "Tesla Model Y", 66000, 10)
print("Student 1 is named ", Student1.name)
print("Student 1 owns a ", Student1.car)
print("Student 1's car costed ", Student1.price)
print("Student 1 rates their car a ", Student1.rating)
print("Student 2 is named ", Student2.name)
print("Student 2 owns a ", Student2.car)
print("Student 2's car costed ", Student2.price)
print("Student 2 rates their car a ", Student2.rating)

print(Student1)
print(Student2)
Student 1 is named  Dillon
Student 1 owns a  Honda Civic
Student 1's car costed  27000
Student 1 rates their car a  9
Student 2 is named  Adi
Student 2 owns a  Tesla Model Y
Student 2's car costed  66000
Student 2 rates their car a  10
{"name": "Dillon", "car": "Honda Civic", "price": 27000, "rating": 9}
{"name": "Adi", "car": "Tesla Model Y", "price": 66000, "rating": 10}