Python Classes Review - Further Practice Discussion

Edit 2: I added a line of code to return a different message for a student with perfect attendance.

Edit 1: I figured out how to do what I was wanting which was to keep count of the number of absences. I converted the boolean values to integers then counted the number of ‘False’ values.

I figured out how to manipulate the different data the way I want to, I think. However, can someone please help me figure out how get my absence counter to work? It works for Pieter because he only has 1 absence, but it also says that Roger has 1 absence when he has 2. I’m sure it’s simple, but my brain is FRIED! I will edit later after I’ve worked on it some more. I think I need to review the options I have for working with the list of values in a dictionary. And I might have just answered my own question…be back soon!

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)
    return grade
  
  def get_avg(self):
    total_grades = 0
    minimum_passing = 65
    for score in self.grades:
     total_grades += score
     average = total_grades/len(self.grades)
    if average >= minimum_passing:
      return "My grade average is: {:1f}\nI am passing! :)".format(average)
    else:
      return "My grade average is: {:1f}\nI am failing! :(".format(average)

  def add_attendance(self, date, record):
    self.attendance[date] = record
    
def get_attendance(self):
    attendance = []
    for x in self.attendance.values():  
        attendance.append(int(x))
    for x in attendance:
      if sum(attendance) == len(self.attendance):
        return "I have perfect attendance!"
      else:
        return "I have {} absence/s recorded.".format(attendance.count(0))
  
  def __repr__(self):
    return "My name is {} and I am in year {}.\nThese are my grades: {}\n{}\nAttendance Record: {}\n{}\n".format(self.name, self.year, self.grades, self.get_avg(), self.attendance, self.get_attendance())

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

  def passing_score(grade):
    minimum_passing = 65
    if grade >= minimum_passing:
      return "This is a passing score!"
    else:
      return "You are failing!"
          
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(75))
pieter.add_grade(Grade(85))

sandro_grades = [90, 80, 95, 75, 65, 50, 45, 40, 35]
roger_grades = [95, 66, 78, 89, 98]

for x in sandro_grades:
    sandro.add_grade(Grade(x))

for x in roger_grades:
    roger.add_grade(Grade(x))

pieter_attendance = [('2/6/2021', True), ('2/5/2021', False), ('2/7/2021', True)]
sandro_attendance = [('2/6/2021', True), ('2/5/2021', True), ('2/7/2021', True)]
roger_attendance = [('2/6/2021', False), ('2/5/2021', False), ('2/7/2021', True)]

for x in list(pieter_attendance):
    date = x[0]
    record = x[1]
    pieter.add_attendance(date, record)

for x in list(sandro_attendance):
    date = x[0]
    record = x[1]
    sandro.add_attendance(date, record)

for x in list(roger_attendance):
    date = x[0]
    record = x[1]
    roger.add_attendance(date, record)  
  
#print(pieter)
#print(sandro)
#print(roger)
2 Likes

This is my code but I don’t know why system annouced that it’s an error in my def attendance even I found it’s kind similar to you and I don’t know why. This is the error it is showed:

Traceback (most recent call last):
  File "script.py", line 46, in <module>
    pieter.attendance(date, status)
  File "script.py", line 18, in attendance
    self.attendance[date] = status
TypeError: 'method' object does not support item assignment
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):

    s = 0

    for student in self.grades:

      s += student.score

    return s / len(self.grades)

  def attendance(self, date, status):

    self.attendance[date] = status

#################################

class Grade:

  minimum_passing = 65

  def __init__(self, score):

    self.score = score

    self.passed = str(self.score >= self.minimum_passing)

  def is_passing(self, score):

    if self.score >= minimum_passing:

       return True

    else:

       return False

  

  def __repr__(self):

    return self.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_attendance = [('2/6/2021', True)]

for i in list(pieter_attendance):

  date = i[0]

  status = i[1]

  pieter.attendance(date, status)

score = Grade(100)

print(score)

Take a look at the following method.

You’re trying to assign a key self.attendance with a value. However, because you didn’t instantiate self.attendance = {} at the beginning of your class, what happens is that it tries to assign the method itself, because it’s also named attendance, which doesn’t work. That’s where you get the TypeError: 'method' object does not support item assignment.

Thank you for your answering, I added the instantiate at the beginning and I fixed the first problem but there is still other error called:

Traceback (most recent call last):
  File "script.py", line 47, in <module>
    pieter.attendance(date, status)
TypeError: 'dict' object is not callable
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)

  def get_average(self):

    s = 0

    for student in self.grades:

      s += student.score

    return s / len(self.grades)

  def attendance(self, date, status):

    self.attendance[date] = status

#################################

class Grade:

  minimum_passing = 65

  def __init__(self, score):

    self.score = score

    self.passed = str(self.score >= self.minimum_passing)

  def is_passing(self, score):

    if self.score >= minimum_passing:

       return True

    else:

       return False

  

  def __repr__(self):

    return self.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_attendance = [('2/6/2021', True)]

for i in list(pieter_attendance):

  date = i[0]

  status = i[1]

  pieter.attendance(date, status)

score = Grade(100)

print(score)

the error says:

TypeError: 'dict' object is not callable

which means you try to call the dictionary as if it where a function. How do we add a key value pair to the dictionary?

1 Like

a quick question:

class Grade:
  minimum_passing = 65 # atribute
  def __init__(self, score):
    self.score = score #is it like saying set this class score to be the 
                      #score passed in?

self.score is the instance variable, which we can then access in other methods

score is the parameter of the init method

why does python has too many self? I’m kind of a beginner in c# and I keep thinking why python has too many self isn’t supposed to be easier ? OOP in c# seems to be less complicated…

Is it normal to think that? Maybe since I’m starting, and I’m not accustomed to the language

self is just a way of addressing object context. Unlike JavaScript, objects in Python do not have a fixed variable (this) so every method must have a formal parameter so it can see the scope above. What we call it is unimportant.

Witness:

>>> class foo():
	def __init__(self, a):
		self.a = a
	def __repr__(self):
		return str(dir(self))

	
>>> b = foo('a')
>>> print (b)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a']
>>> 

And now,

>>> class foo():
	def __init__(this, a):
		this.a = a
	def __repr__(this):
		return str(dir(this))

	
>>> b = foo('a')
>>> print (b)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a']
>>> 
2 Likes

I can’t figure out why my code is producing the following:

[<main.Grade object at 0x7fcd59914f28>, <main.Grade object at 0x7fcd59914f60>, <main.Grade object at 0x7fcd59914f98>]
<bound method Student.get_average of <main.Student object at 0x7fcd59914ef0>>

class Student: def __init__(self, name, year): self.name = name self.year = year self.grades = [] self.average = 0 self.total = 0 def add_grade(self, grade): if type(grade) == Grade: self.grades.append(grade) else: pass def get_average(self): for each in self.grades: self.total += each self.average = self.total / len(self.grades) return self.average 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) pieter.add_grade(Grade(100)) pieter.add_grade(Grade(90)) pieter.add_grade(Grade(80)) print(pieter.grades) print(pieter.get_average)

Please help.

For starters, print(pieter.get_average). When we examine the class definition, get_average is a method, not an attribute that carries a value. Fix this, and return if more issues persist. We did spot another suspicious bit of code but will wait until this fix is in.

1 Like

Thank you for the tip. I fixed it and I changed:

self.grades.append(grade.score)

I realized that grade was being received by the method as an object and not an int. So the method was adding the objects to the list - which makes sense why get_average wasn’t working properly either.

2 Likes

yes, finally i can see it. if i tried adding a score, just as int not as class Grade, it wouldn’t work and it makes sense.

syntax is really complicated and not intuitively obvious though. i think i’ll start calling my objects whatever_obj, just so it’s immediately obvious for me, that when i pass it as an argument of a function of some other class, that it is indeed an object (with it’s own properties).

yes, finally i can see it. if i tried adding a score, just as int not as class Grade, it wouldn’t work and it makes sense.

syntax is really complicated and not intuitively obvious though. i think i’ll start calling my objects whatever_obj, just so it’s immediately obvious for me, that when i pass it as an argument of a function of some other class, that it is indeed an object (with it’s own properties).

Hello, this is my full code, hope it helps someone out.

PS. If you’re looking for inspiration or you’re having a hard time coding:

This is my second time trying to get through CS101: Introduction to Programming. The first time i didn’t even bother coding the bonuses (in all CS101) because i thought i couldn’t do it. I kept looking at the forums wondering how people came up with the solutions for the bonuses and thinking if i would ever do that or i was just wasting my time trying to learn programming. Just keep trying, it gets easier :grinning_face_with_smiling_eyes:

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):
    num = 0
    for i in self.grades:
      num += i.score
    return num / len(self.grades)
  
  def __repr__(self):
    return self.name

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 "This is a passing grade"
    else:
      return "This is not a passing grade"

#print(Grade(55).is_passing())
#pieter.add_grade(Grade(100))
#pieter.add_grade(Grade(90))
#print(pieter.get_average())

pieter.attendance = {"monday": True, "tuesday": False}
roger.attendance = {"monday": False, "tuesday": True}

def get_attendance(student):
  for date, value in student.attendance.items():
    if value:
      print("{student} did attend on {date}".format(student=student, date=date))
    else:
      print("{student} didn't attend on {date}".format(student=student, date=date))

#get_attendance(pieter)
#get_attendance(roger)
3 Likes


this is how I did the get_average method

Thank you for your codes, it does really help seeing how other people think through different problems @laviedfleur Your words are encouraging :slight_smile:

1 Like

ok, hi, please help, I can`t find error. I can only once store in dictionary…why???
class Student:
def init(self, name, year):
self.name=name
self.year=year
self.grades=
self.aattendance={}
def add_grade(self,grade):
if type(grade) is Grade:
self.grades.append(grade.score)
def get_average(self):
sum=0
for grade in self.grades:
sum+=grade
return sum/len(self.grades)

def attendance(self, date, attendance):
self.date=date
self.attendance=attendance
self.aattendance[self.date]= self.attendance
return self.aattendance
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 True
return False
pieter.add_grade(Grade(100))
pieter.add_grade(Grade(50))
pieter.add_grade(Grade(75))

pieter_grades=pieter.grades
print(pieter_grades)
a=Grade(100)
print(a.is_passing())
print(pieter.get_average())

p=pieter.attendance(‘26.07.’, ‘present’)
print(p)
pieter.attendance(‘25.07.’, ‘present’)

Output:
[100, 50, 75]
True
75.0
{‘26.07.’: ‘present’}
Traceback (most recent call last):
File “script.py”, line 44, in
pieter.attendance(‘25.07.’, ‘present’)
TypeError: ‘str’ object is not callable

You seem to have a method (function) named attendance and a parameter attendance and a self.attendance
These may interfere with each other or overwrite each other in some cases.

Thanks, it was in self.date and self.attendance I just removed object self and it worked.