How can I access Pieter's grade after it has been added?

It returns 1 instead of None. No real purpose other than to confirm that the loop ran to completion (printed all the grades). Nothing else to read into this.

1 Like

Here’s my shot at everything.

@knokodil Your code helped me understand __rpr__ better, thank you for posting! I included two ways to access/print the Student Class’s instance attributes. The first one I came up using the googles, but your code is much prettier.

If anyone also had questions about the use of __repr__ vs __str__ I think this video helps a bunch.

class Student:
  def __init__(self, name, year):
    self.name = name
    self.year = year
    self.grades = []
    self.attendance = {}
  def __repr__(self):
    return f'{self.__class__.__name__}\
    ({self.name}, {self.year}, {slef.grades},{self.attendance}, {self.attendance}'
 
  def add_grade(self, grade):
    if type(grade) == Grade:
      self.grades.append(grade)
  
  def get_average(self):
    if not len(self.grades) == 0:
      total =  0
      for grade in self.grades:
        total += grade.score
      average =  total / len(self.grades)
      print(f"{self.name}'s score averages out to {round(average)}.")
    else:
      print(f"Student {self.name} does not have any recorded grades.")
  def add_attendance(self, the_date, present = True):
    try:
      from datetime import datetime 
      x = datetime.strptime(the_date, "%m/%d/%Y")
      if present == True:
        self.attendance[datetime.strftime(x, "%m/%d/%Y")] = True
        print("attendance recorded")
      elif present == False:
        self.attendance[datetime.strftime(x, "%m/%d/%Y")] = False
        print("attendance recorded")
    except ValueError:
      print("Error: Last date not recorded. Please input date as MM/DD/YYYY.")

  
class Grade:
  minimum_passing = 65
  def __init__(self, score):
    self.score = score
  def __repr__(self):
    # return f'{self.__class__.__name__} ({self.score})'
# tells python to represent class and attribute formatted as class (attribute) str
    return str(self.score)
# tells python to represent score attribute as string
  def is_passing(self):
    if self.score >= self.minimum_passing:
      print(f"A score of {self.score} is a passing grade.")
    else:
      print( f"A score of {self.score} is not a passing grade.")
 

roger = Student("Roger van der Weyden", 10)
sandro = Student("Sandro Botticelli", 12)
pieter = Student("Pieter Bruegel the Elder", 8)

pieter.add_grade(Grade(100))
pieter.add_grade(Grade(90))
pieter.add_grade(Grade(70))

pieter.get_average()  # prints rounded average inside message
sandro.get_average()  # prints Student does not have any recorded grades.

print("Pieter's grades: ", pieter.grades) # prints Pieter's grades:  [100, 90, 70]
print("Pieter's grade year: ", pieter.year) # prints Pieter's grade year:  8

pieter.add_attendance("05/12/2021", False) # prints attendance recorded
pieter.add_attendance("05/13/2021", True) # prints attendance recorded
pieter.add_attendance("05/14/2021", True) # prints attendance recorded
pieter.add_attendance("May 15th, 2021", False) # prints error message

print("Attendance:", pieter.attendance)
#prints Attendance:{'05/12/2021': False, '05/13/2021': True, '05/14/2021': True}

Not sure how efficient this is, especially the attendance method. For that my thinking was:

  1. Take in a string
  2. Use strptime to convert it into a datetime object
  3. Convert the datetime object back into a customized string so all dates return the same format via strftime
  4. Throw everything into try and except blocks to catch errors incase of incorrect date input.

Comments welcome!

1 Like

@mtf Sorry was trying to reply to the topic post, but you’re input is always welcome!

I’m having some problems with these lines of code (I think :slight_smile:):

def add_grade(self, grade):
    if type(grade) == Grade:
      self.grades.append(grade)

At the end of my entire code, I added pieters grades. But the list ā€œself.gradesā€ is empty. If I dont’t unse the ā€œif type ā€¦ā€ it looks like it is supposed to do. Does somebody know why and what I can do to fix it?

Here’s also the Grade class code:

class Grade:
  minimum_passing = 65

  def __init__(self, score):
    self.score = score

  def is_passing(self):
    if self.score >= self.minimum_passing:
      print("The grade has a passing score.")
    else:
      print("The grade does not have a passing score.")

I don’t see you call the add_grade method anywhere? Could you post your full code?

Thanks for your answer. Here is my full code:

class Student:
  def __init__(self, name, year):
    self.name = name
    self.year = year
    self.grades = []

  def add_grade(self, grade):
    if type(grade) == Grade:
      self.grades.append(grade)

  def get_average(self):
    average = 0
    for grade in self.grades:
      average += grade / len(self.grades)
    print("The student's average score is: " + str(average))
    return average

class Grade:
  minimum_passing = 65
  def __init__(self, score):
    self.score = score

  def is_passing(self):
    if self.score >= self.minimum_passing:
      print("The grade has a passing score.")
    else:
      print("The grade does not have a passing score.")

roger = Student("Roger van der Weyden", 10)
sandro = Student("Sandro Botticelli", 12)
pieter = Student("Pieter Bruegel the Elder", 8)

pieter.add_grade(100)
pieter.add_grade(50)
pieter.add_grade(70)
pieter.add_grade(80)

pieter.get_average()

pieter.attendance = {"Monday": False, "Tuesday": True}

print(pieter.grades)

pieter = Grade(100)
pieter.is_passing()

when adding grades:

pieter.add_grade(100)
pieter.add_grade(50)
pieter.add_grade(70)
pieter.add_grade(80)

you should not pass integers as argument values. You should make instances of Grade class (which takes an integer as argument for score parameter), then pass these instances/objects of Grade to add_grade method

Thank you very much for your help. I will have to take a deeper look at this … :slight_smile:

So many questions as I learn classes :face_exhaling:. First one below. Thank you to all you talented people who support the forums. I think I looked through all the posts and didn’t see a relevant post…
This is about creating an average score attribute. I also tried to make it a method. The method was intended to take in self, the self grades list attribute but that also threw an error: TypeError: unsupported operand type(s) for +: ā€˜int’ and ā€˜Grade’. What am I not understanding? I undertand the zero error if I didn’t have any grades in yet (for which I also tried to write a try/except and realized I was REALLY getting ahead of myself :P)

class Student(): def __init__(self, name, year): self.name = name self.year = year self.grades = [] self.score = sum(self.grades)/len(self.grades) def add_grade(self, grade): if type(grade) == Grade: self.grades.append(grade) # def score_avg(self, self_grade_list_attribute): # return sum(self_grade_list_attribute)/len(self_grade_list_attribute) roger = Student("Roger van der Weyden", 10) sandro = Student("Sandro Botticelli", 12) pieter = Student("Pieter Bruegel the Elder", 8) class Grade(): minimum_passing = 65 def __init__(self, score): self.score = score def is_passing(self, score): minimum_passing = 65 if score >= minimum_passing: return "Your current grade of {grade} meets the minimum reuirements for passing.".format(grade = score) else: return "Your current grade of {grade} does not meet the minimum reuirements for passing.".format(grade = score) pieter.add_grade(Grade(100)) pieter.add_grade(Grade(50)) pieter.add_grade(Grade(80)) getattr(pieter.score) #pieter.score_avg(pieter.grades) #TypeError: unsupported operand type(s) for +: 'int' and 'Grade'

self.grades is a lost of Grades object/instances

so the simplest solution would be to loop over self.grades (in the score_avg method) and get the .score of each grade, add them to a total variable and then after the loop divide by the length of the list

1 Like

Okay with this I basically want to go through the list grades which is a list of objects where it will only give me the memory address where the object lays and there I want to access the attribute score. Did I get it right?

Is there any other way like pieter.grades[0].score or something? Or is a for loop inevitable?

Thank you in advance!

The most sensible case would be a loop so no grades are missed.

1 Like

I assume you would have to access to the object property with a for loop, for example:

for iterable in pieter.grades:
print(iterable.score)

but self.grades is still a student class property which upon implementing the line

Pieter.add_grade(Grade(100))

should update the list to have the element 100. Shouldn’t we be able to get the updated list, directly calling on the instance like so?

print(pieter.grades)

but self.grades is still a student class property which upon implementing the line

Pieter.add_grade(Grade(100))

should update the list to have the element 100. Shouldn’t we be able to get the updated list, directly calling on the instance like so?

print(pieter.grades)

Recall that the value is assigned to a `score’ attribute of the Grade class.

This was the solution I needed! Thank you

Sorry if this has been asked, but why pass it through the Score class at all?

What is the disadvantage to rewriting add_grade this way?

def add_grade(self,grade): self.grades.append(grade)

and then we can add new grades, and call them like so:

pieter.add_grade(100) print(pieter.grades)

Forgive me for not scrolling up to find a link to the lesson. As I recall this exercise has two classes, Grade and Student. Please correct me if I’m wrong. We’re focused on the Grade class, which I’m pretty sure has a score attribute.

>>> class Grade:
        def __init__(self, score):
            self.score = score


>>> a_grade = Grade(99)
>>> a_grade.score
99
>>> 

A Student would necessarily handle more than one grade (accumulate) and thus have a reference object to ā€˜contain’ them. One would guess a student class might look like,

class Student:
    def __init__(self):
        self.grades = []
    def add_grade(self, grade):
        self.grades.append(grade)

Knowing that every grade entry is a Grade object, we need to keep that in mind when polling the grades attribute.

    def get_grades(self):
        return [x.score for x in self.grades]

Under this dictate we get,

>>> peter = Student()
>>> peter.add_grade(Grade(99))
>>> peter.add_grade(Grade(89))
>>> peter.add_grade(Grade(95))
>>> peter.add_grade(Grade(85))
>>> peter.add_grade(Grade(94))
>>> peter.get_grades()
[99, 89, 95, 85, 94]

This is so neat and tidy. Thanks for sharing. Excuse my ignorance as I’m still trying to better understand this Class topic. But why is it ok for us to code self.grades = [] inside the def __init__(self, name, year) method under the class Student? The parameters are only self, name, year … not grades. I thought that we can only do the .something code if the something is designated as a parameter in the method or function?