How to check for passing in the Grade class?

Hi,
I also don’t understand how is it works… :frowning:

In my code pieter.grades is a list
type(pieter.grades) # <class ‘list’>
pieter.grades.score stop running with AttributeError: ‘list’ object has no attribute ‘score’

Here is my 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):
    for grade in self.grades:
      pass

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):
    return self.minimum_passing <= self.score

peitersGrade = Grade(100)
pieter.add_grade(peitersGrade)

print(pieter.grades[0].score)

# AttributeError: 'list' object has no attribute 'score'
print(pieter.grades.score) 


#print(pieter.get_average)

yes, it is.

the list contains elements, these elements have a score attribute. You seem to grasp this based on this line of code:

print(pieter.grades[0].score)

we could write a print_grades method for students for example, which will print the grade of each score.

So I leave to pieter.grades.score syntax because it will never works…
I handle the grades as a list

Here is my solutions...
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):
    added = 0
    for grade in self.grades:
      added += grade.score
    return added / len(self.grades)
  
  def get_scores(self):
    return [self.grades.score for self.grades in self.grades]

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):
    return self.minimum_passing <= self.score

peitersGrade = Grade(100)
sandrosGrade = Grade(63)
pieter.add_grade(peitersGrade)
pieter.add_grade(Grade(61))
sandro.add_grade(sandrosGrade)

print(pieter.grades[0].score)
print(pieter.grades[0].is_passing())
print(pieter.get_average())
pieter.attendance = {
  "21.06.2020": True
}
print(pieter.attendance)
#print(sandro.grades[0].score)
print(pieter.get_scores())






I hope it is right… (otherwise I don’t understand anything…)
I also added a get_scores() method to the Student class. This is return a list of scores.

Which suggests to us that you created this code from an example in another post…

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

That can hardly be expected to give any meaning result. self.grades is a list of Grade objects. It is those objects that have a score attribute, not the list itself.

return [grade.score for grade in self.grades]

will return a list of just the score values. Above, grade is a Grade object, hence it has the requisite attribute.

This is my 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):
    total=0
    print(self.grades)
    print(type(self.grades))
    for i in self.grades:
      total+=i.score
    return(total/len(self.grades)) 
  
class Grade:
  minimum_passing=65
  def __init__(self, score):
    self.score=score
  def is_passing(self):
    return(self.score>=Grade.minimum_passing)

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

pieter.add_grade(Grade(100))
#print(dir(pieter))
a=Grade(50)
print(a.is_passing())
print(pieter.get_average())

The part that I don’t understand is the following (lines 13-15 of above).

   for i in self.grades:
      total+=i.score
    return(total/len(self.grades)) 

Considering that I defined an instance attribute of type list (self.grades=[ ]) in line 5 of my main code, and in line 13, using a For loop, I’m iterating through elements of that list, then why those elements are not accessible directly? and why should I treat it as a class and add i.score to total in line 14, instead of directly total+=i? I mean if the elements are already accessible for the For loop, why can’t I print or use them? It shows memory address if I use print(i) inside that For loop. If it’s a memory address, how iteration is working in For loop for this list?

Thanks in advance for answering my questions.

That list is not of plain numbers but of object instances. The are Grade instances, each with their own score attribute. It is that attribute that holds the grade value.

1 Like

Thanks mtf for answering.
So, it’s a list of object instances. Then at line 11, print(self.grades), I printed the list expecting that it will show a list of memory addresses, representing those object instances, but it just shows another memory address, not a list. If it’s a list, shouldn’t it print the whole list regardless of types of its elements? The list is working for iteration and the size of the list can be retrieved, but cannot be printed out. How does it work?

It doesn’t know how to. We know about the implementation of the Grade class, and its use within the Student class. That’s our responsibility to ensure that the program knows how to find and extract the data.

x = 0
for i in self.grades:
    x += i.score
return x / len(self.grades)

If we wish to print out the list of grades, then we need to iterate the list as above, only this time, print i.score. When we try to print the list directly we get only the stubs of each instance, which is useless to us.

1 Like

This classes section has really thrown me and I don’t think it’s very well explained on CodeAcademy. I’ve just about got my head around everything that’s gone on in each lesson now but I’m not sure how to call the methods and get any outputs… This hasn’t been explained it seems and having looked through this thread I don’t think I’m on my own here!

The below is what I’ve coded but how on earth am I supposed to actually find out if Pieter is passing now? What sort of print statement would I need to write? It’s hard to troubleshoot you’re own code when you don’t know how to print out in the first place…

class Student:

def init(self, name, year):

self.name = name

self.year = year

self.grades = []

def add_grade(self, grade):

if type(grade) is Grade:

  self.grades.append(grade)      

class Grade:

minimum_passing = 65

def init(self, score):

self.score = score

def is_passing(self, score):

if self.score >= Grade.minimum_passing:

  return 'You have passed!'

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.is_passing()

1 Like

Hello @joshmears169 and welcome to the Codecademy Forums!

Because is_passing() is a method of the Grade class, you can’t call pieter.is_passing() because pieter is of the Student class. You can only call is_passing() on an instance of the Grade class.

This means you can check if a certain grade meets the minimum passing score. If you want to find out if Pieter is passing, you can find Pieter’s average and make it an instance of the Grade class, then call is_passing().

2 Likes

Hi there! Thanks a lot for your reply.

I am still very confused… I’ve used the below:

a = Grade(90)

print(a.is_passing())

and got the following error now…

Traceback (most recent call last):
File “script.py”, line 32, in
print(a.is_passing())
TypeError: is_passing() missing 1 required positional argument: ‘score’

I understand your point on the different class methods now so I created a new instance for Grade but I don’t understand why this doesn’t work now.

Your method is expecting a score, but it doesn’t need to. It can find the score on self.

1 Like

Thanks @mtf, really helpful!

1 Like

i was using self.grades += grade and that was giving me an error Grade is not iterable. But when i changed it to the append method it worked. please explain it why it was giving an error.

When we use the += operator, Python is looking for a sequence. A solitary object instance is not a sequence, and therefore not iterable. A list with just one value is still iterable.

self.grades += [grade]

Now it will work. Note how this emulates what the list.extend() method does.

list.append() is suitable for adding a single value to the end of a list, but not so for adding a sequence of values unless they are to retain their data structure. Extending is taking two lists and concatenating them.

def add_grade(self, grade):

if isinstance(grade, Grade):

  self.grades.append(grade)

else:

  return

You can also use the isinstance() method to compare the type.