FAQ: Learn Python: Classes - Review


#1

This community-built FAQ covers the “Review” exercise from the lesson “Learn Python: Classes”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Computer Science

FAQs on the exercise Review

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!


#2

Did anyone try the the bonus practice in the review?

I seem to be having a challenge with the including the get_average() method.

One thing I observed was that the .grades was printing out in string representation form and when I included repr in an attempt to debug it, I got a ‘NoneType’ error traceback. Here is code below: (can anyone spot the error?)

class Student(object):
attendance = {}
def init(self, name, year):
self.name = name
self.year = year
self.grades = list()

def repr(self):
print(self.name, self.year, self.grades)

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

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):
if self.score > self.minimum_passing:
return “Yes”
else:
return “No”

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

print(pieter.grades)


#3

One thing that you did wrong is writing init keyword without underscores before and after it. So it should be like this to work: __init__.


#4

I have the same question, did anybody figure it out


#5

I just figured you need to add the repr() method in your grade class to print out the list of grades without just showing the memory location

class Grade:
minimum_passing = 65

def init(self, score):
self.score = score
def repr(self):
return str(self.score)


#6

Hey thanks.

I did a copy and paste but that didnt work…I have it in dunder in the actual code


#7

Hey thanks. That worked.

But I’m still stuck on why my get_average does not work.

Did you by chance use a for loop?

def get_average(self):
total = 0
for grade in self.grades:
total += grade
return total

I get unsupported type error.


#8

In case you struggled with this as well. I just made Grade a subclass of ‘int’ and it seemed to recognize this.


#9

How did you test your code? I guess I’m having a little of a hard time understanding this, so having a harder time verifying if my code is right.

Specifically for the average() and the .attendance parts.

Here is what I have so far:

import datetime
time_now = datetime.datetime.now()

print()

class Student:
def init(self, name, year, today):
self.name = name
self.year = year
self.grades =
self.attendance = {}
if today == time_now.strftime("%x"):
self.attendance.update({today:True})
else:
self.attendance.update({today:False})

def add_grade(self, grade):
if type(grade) == Grade:
self.grades.append(grade)
def get_average(self):
average = self.grade.mean()
return average

class Grade:
minimum_passing = 65

def init(self, score):
self.score = score
def is_passing(self):
if self.score >= minimum_passing:
return “Pass”
else:
return “Fail”
def repr(self):
return str(self.score)

roger = Student(“Roger van der Weyden”, 10, “11/22/2018”)
sandro = Student(“Sandro Botticelli”, 12, “11/22/2018”)
pieter = Student(“Pieter Bruegel the Elder”, 8,“11/22/2018”)
pieter.add_grade(Grade(100))


#10

self.grades.append(grade)
–> self.grades.append(grade.score)


#11

My code is follow:
class Student:
def init(self, name, year):
self.name = name
self.year = year
self.grades =
self.attendance = {}

def add_grade(self, grade):
if type(grade) == Grade:
self.grades.append(grade.score)
def get_average(self):
return sum(self.grades)/ len(self.grades)


#12

Hey hello did anyone solve the review part correctly?
This is my code:

"""
A class is a template for a data type. It describes the kinds of information that class will hold and how a programmer
will interact with that data. Define a class using the class keyword. PEP 8 Style Guide for Python Code
recommends capitalizing the names of classes to make them easier to identify.
"""
"""Instantiation
A class doesn't accomplish anything simply by being defined. A class must be instantiated. In other words, we must 
create an instance of the class, in order to breathe life into the schematic.
Instantiating a class looks a lot like calling a function. We would be able to create an instance of our defined CoolClass as follows:

"""
# example : cool_instance = CoolClass()

"""Above, we created an object by adding parentheses to the name of the class. We then assigned that
 new instance to the variable cool_instance for safe-keeping.
"""
"""Instantiation takes a class and turns it into an object, the type() function does the opposite of that. When called 
with an object, it returns the class that the object is an instance of."""
"""Methods are functions that are defined as part of a class. The first argument in a method is always the object that is 
calling the method. Convention recommends that we name this first argument self. Methods always have at least this one argument.
We define methods similarly to functions, except that they are indented to be part of the class.
"""
# Little project about classes an OOB
import datetime
time_now= datetime.datetime.now()
class Student:


    def __init__(self, name, year,today):
        self.name = name
        self.year = year
        self.grades = []
        self.attendance = {}




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



    def get_average(self):
        return sum(self.grades) / len(self.grades)


class Grade:

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

    def __repr__(self):
        return str(self.score)



roger = Student("Roger van der Weyden", 10,"11/22/2018")
sandro = Student("Sandro Botticelli", 12,"11/22/2018")
peter = Student("Pieter Bruegel the Elder", 8,"11/22/2018")
print(roger)
print(sandro)
print(peter)

peter.add_grade(Grade(100))
print(roger.attendance)
print(peter.grades)
print(peter.get_average())
print(peter.attendance)

def is_passing(self):

    if self.score >self.minimum_passing:
        return "Is passing"
    else:
        return "Is failing"
def _update_attendance(self):

    if self.today == time_now.strftime("%x"):

        self.attendance.update({self.today:True})
    else:
        self.attendance.update({self.today:False})

the output i get:
<main.Student object at 0x0000000002945208>
<main.Student object at 0x000000000290B9E8>
<main.Student object at 0x000000000290BA58>
{}
[100]
Traceback (most recent call last):
line 69, in
print(peter.get_average())
, line 45, in get_average
return sum(self.grades) / len(self.grades)
TypeError: unsupported operand type(s) for +: ‘int’ and ‘Grade’


#14

The code attached below includes a few comments and print statements to check the code. The attendance dictionary could be updated from a spreadsheet, if needed. It is not type-checked here.

class Student:
  
  def __init__(self, name, year):
    self.name = name
    self.year = year
    self.grades = [] # type: List
    self.attendance = {}  # type: Dict
  
  def __repr__(self):
    return "{0} is in year {1}. This student's grades are {2}.".format(self.name, self.year, self.grades)
      
  def add_grade(self, grade):
    self.grade = grade
    if type(self.grade) == Grade: 
      self.grades.append(self.grade.score) # attribute from Grade
  
  def get_average(self):
    return "{0}'s average is {1}.".format(self.name, sum(self.grades) / len(self.grades))
  
  
class Grade:
  minimum_passing = 65
  
  def __init__(self, score):
    self.score = score
    
  def is_passing(self):
    return self.score >= self.minimum_passing
    
roger = Student("Roger van der Weyden", 10)
sandro = Student("Sandro Botticelli", 12)
pieter = Student("Pieter Bruegel the Elder", 8)

for i in range(95, 101):
    pieter.add_grade(Grade(i))

pieter.attendance["2019-01-08"] = True
pieter.attendance["2019-01-07"] = False

print(roger)
print(sandro)
print(pieter)
thumbs_up = Grade(99)
thumbs_down = Grade(64)

print(pieter.get_average()) # use get_average() vice get_average
# print(pieter.get_average) # uncomment this to see what prints
print(thumbs_up.is_passing()) # True for this example
print(thumbs_down.is_passing())

print(pieter.attendance)

#15

giulia22,

grade is of type Grade. While grade is an integer, Grade is not. You want to pass the score from Grade like this:

def add_grade(self, grade):
    self.grade = grade
    if type(self.grade) == Grade: 
      self.grades.append(self.grade.score) # attribute from Grade

#16

I notice the above examples are using type(), but the SCT may be expecting isinstance()

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

For the average, I created a helper method that returns a list of numbers…

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

Now the method can be called upon to simplify get_average()

  def get_average(self):
    grades = self.get_grades()
    return sum(grades) / len(grades)

The is_passing method can be handed the average…

print(Grade(pieter.get_average()).is_passing())

#17
class Student:
  pass
  def __init__(self, name, year):
    self.name = name
    self.year = year
    self.grades = []
  def add_grade(self, grade):
    self.grade = grade
    if type(self.grade) == type(Grade):
      (self.grades).append(self.grade)
    else:
      False


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

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

I am having trouble moving past step 8:
Create a new Grade with a score of 100 and add it to pieter 's .grades attribute using .add_grade() .

I have tried many different variations. Some have come back asking if I added grade to pieter’s grades using add_grade? another says my function has no len()…

I can’t seem to break this code. any help?


#18
def add_grade(self, grade):
    self.grade = grade
    if type(self.grade):
      (self.grades).append(self.grade)
    else:
      False

I took away the type(self.grade) == type(Grade):

and worked…not sure why other than there was no obstruction to perform the add_grade function…


#19

That line may be removed, since the body contains code it serves no purpose.

That’s creating a new attribute that also serves no real purpose. Work with the parameter and don’t assign it to the object.

Let’s play around with this…

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

		
>>> a = Grade(100)
>>> type(a)
<class '__main__.Grade'>
>>> type(a) == 'Grade'
False
>>> type(a) == Grade
True
>>> 

So we see that type(object) can be equated to the class.

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

The else clause in this instance could be either, return False or not have a default action.

Another possibility might be to raise a TypeError exception with a message to the user. No return will be required.


#21

Hello everyone. I have done with it.
This is my code:

from datetime import datetime
current_time = datetime.now().strftime('%b %d, %Y')

class Student:
  pass
  def __init__(self, name, year, attendance):
    self.name = name
    self.year = year
    self.grades = []
    self.attendance = {}
    if attendance:
    	self.attendance[current_time] = True
    else:
    	self.attendance[current_time] = False
  def add_grade(self, grade):
    if type(grade) == Grade:
      self.grades.append(grade)
  def get_average(self):
    total_grade = 0
    for grade in self.grades:
      total_grade += grade.score
    return total_grade / len(self.grades)
  
class Grade:
  minimum_passing = 65
  def __init__(self, score):
    self.score = score
  def is_passing(self):
    if self.score > self.minimum_passing:
      return "Yes"
    return "No"

# test
roger = Student('Roger van der Weyden', 10, True)
sandro = Student('Sandro Botticelli', 12, False)
pieter = Student('Pieter Bruegel the Elder', 8, True)
pieter.add_grade(Grade(100))
pieter.add_grade(Grade(98))
pieter.add_grade(Grade(90))
print(pieter.get_average())
print(Grade(pieter.get_average()).is_passing())
print(pieter.attendance)

#22
self.grades = []

When I use the add_grade method as defined below

def add_grade(self, grade):
  if type(grade) is Grade:
    self.grades.append(grade)
pieter.add_grade(Grade(100))

and then print out Pieter’s grades list

print(pieter.grades)

I see that Grade(100) has been appended to the list, rather than 100, the integer. I get a result of [<__main__.Grade object at 0x7f6ace7406a0>] when printed out.

How might the add_grade method yield integers into Pieter’s grades list?

If I enter pieter.add_grade(100), it doesn’t satisfy the method because the integer 100 is not of class Grade.

Would I have to add a grade argument into the constructor and then simply append self.grade into the self.grades list? I’m just not sure what solution the exercise wants me to find… A list with content such as [<__main__.Grade object at 0x7f6ace7406a0>] does not strike me as useful.

This is in reference to parts 7 + 8 of the exercise.