Python beginner OOP functions - python

Can you help me to solve the problem, why am I not able to call my functions? I try to calculate the average mark of all student objects created but it somehow doesnt work.
class Student:
anz = 0
def __init__(self, vorname, nachname, studetnId, averageMark):
self.vorname = vorname
self.nachname = nachname
self.studentId = studetnId
self.averageMark = averageMark
Student.anz += 1
def totalAverageMark(self, input):
summe = 0
for s in input:
summe += self.averageMark
return (summe / Student.anz)
def getName(self, arr):
for s in arr:
return self.nachname
students = [Student("Maxine", "Muster", 2, 1.0), Student("Bert", "Beispiel", 1, 2.0)]
print(students.getName())
print(students.totalAverageMark())
It says: AttributeError: 'list' object has no attribute 'totalAverageMark'

students is a list of your students. List has not functions getName and totalAverageMark. You can use them only with object of Student class.
Simplest way to get total average mark of students:
class Student:
anz = 0
def __init__(self, vorname, nachname, studetnId, averageMark):
self.vorname = vorname
self.nachname = nachname
self.studentId = studetnId
self.averageMark = averageMark
Student.anz += 1
students = [Student("Maxine", "Muster", 2, 1.0), Student("Bert", "Beispiel", 1, 2.0)]
sum = 0
for s in students:
sum += s.averageMark
print(f"Total average mark is {sum / len(students)}")

Student define attributes of a single student only single. to get the collective result for example avg mark of all student, you need to create a class (that bind all students say) that defines the attribute of the class ie there students.
below is a simple implementation what you are trying to do using OOPs
class Student:
def __init__(self, vorname, nachname, studetnId, averageMark):
self.vorname = vorname
self.nachname = nachname
self.studentId = studetnId
self.averageMark = averageMark
class Students:
def __init__(self, students_list: list):
self.students = students_list
def avg_marks(self):
total_students = len(self.students)
marks = sum(student.averageMark for student in self.students)
return marks/total_students
students = [Student("Maxine", "Muster", 2, 1.0), Student("Bert", "Beispiel", 1, 2.0)]
student_data = Students(students)
print(student_data.avg_marks())

To iterate through the list and print out the result for each student
for student in students:
print(student.getName())
print(student.totalAverageMark())
Or to access an individual student
students[0].getName()

Related

How to return all objects from a class?

I created the following class from which I can "create" students:
import itertools
class Student (object):
id_iter = itertools.count()
def __init__(self, studentName):
self.studentName = [studentName, next(self.id_iter)]
def __str__(self):
return str(self.studentName)
This way, each student gets a unique ID starting from 0. My example list:
stud1 = Student("Justa Student")
stud2 = Student("Another One")
stud3 = Student("One Morestudent")
I'd like to create a function which would return a similar looking list with both the student names and student IDs (I created this list with another, long code):
Desired output list
The output would return all students and their respective IDs. Later on, I'd like to have another function with removing students as well, I'm thinking of making the function with a for loop going until the highest ID, but I can't properly return stuff with the class.
First, I suggest NOT storing both the name and id in a variable named studentName. This is just confusing.
Instead, you can have a separate studentId field:
import itertools
class Student (object):
id_iter = itertools.count()
def __init__(self, studentName):
self.studentName = studentName
self.studentId = next(self.id_iter)]
def __str__(self):
return str(self.studentName)
Now to create a list, you can make another method that does it:
def createStudents(names):
return [Student(name) for name in names]
To use this, you have to pass in a list of names:
students = createStudents(["Alice", "Bob", "Charles"])
Now you can print out the list of students with a for loop. I will leave this as an exercise for the reader.
You could create two class methods to store and remove registered students at the class level, meaning you have access to all students that were instantiated by the Student class during your program's process.
import itertools
class Student (object):
id_iter = itertools.count()
registeredStudents = {}
def __init__(self, studentName):
self.studentName = [studentName, next(self.id_iter)]
self.registeredStudents[self.studentName[0]] = self.studentName[1]
def __str__(self):
return str(self.studentName)
#classmethod
def registered_students(cls):
return [[k, v] for k, v in cls.registeredStudents.items()]
#classmethod
def remove_student(cls, studentName):
cls.registeredStudents.pop(studentName)
stud1 = Student("Justa Student")
stud2 = Student("Another One")
stud3 = Student("One Morestudent")
print(Student.registered_students()) # [['Justa Student', 0], ['Another One', 1], ['One Morestudent', 2]]
# or
print(stud1.registered_students()) # [['Justa Student', 0], ['Another One', 1], ['One Morestudent', 2]]
# remove student
stud1.remove_student('Justa Student')
# or --> Student.remove_student('Justa Student')
# see remaining students
print(Student.registered_students()) # [['Another One', 1], ['One Morestudent', 2]]

Editable Callers for Class Attributes - Python

I am working on a mock Student Database using OOP in python, and I am trying to use a function to search for certain parameters of a Class.
In the following example, School is a large class that holds instances of Students as one of its arguments. Hence (For Student in School.Student)
found_list = []
class Student():
def __init__(self, name, age, gender, name_of_school, class_type):
self.name = name
self.age = age
self.gender = gender
self.name_of_school = name_of_school
self.class_type = "S"
Example_Student = Student("Joseph", 8, "male", "The School", "S")
gender_to_be_found = input("Enter the gender to be searched for ")
for Student in School.Student:
if Student.gender == gender_to_be_found:
found_list.append(Student)
This works as a principle but I am wanting to do it in the below format, so I can search for various attributes of a Class through one function
def search_for(value_to_be_found, values_to_searched_from, end_list, class_argument):
if end_list != values_to_searched_from:
for possible_targets in value_to_be_found:
for possible_matches in values_to_searched_from:
try:
if possible_targets == possible_matches.class_argument:
end_list.append(possible_matches)
except:
pass
else:
for possible_targets in value_to_be_found:
for possible_matches in values_to_searched_from:
try:
if possible_targets != possible_matches.class_argument:
end_list.remove(possible_matches)
except:
pass
so that I can pass in the (class_argument) "gender"
and automatically search for any Student.gender that matches my value_to_be_found
search_for("Joseph", School.Student, found_list, "name")
Clearly this proposed method (above) is non-functional, but I feel like there is a way to do this that I have not managed to quite achieve.
This error is produced:
AttributeError: object has no attribute 'class_argument'
Thanks in advance for any help :)
You could add a search function to School, using getattr to access attributes of an object:
class Student():
def __init__(self, name, age, gender, name_of_school, class_type):
self.name = name
self.age = age
self.gender = gender
self.name_of_school = name_of_school
self.class_type = "S"
class School:
def __init__(self):
self.students = []
def add(self, student):
self.students.append(student)
def search(self, value, search_attribute):
result = []
for s in self.students:
student_value = getattr(s, search_attribute, None)
if student_value == value:
result.append(s)
return result
s1 = Student("Joseph", 8, "male", "The School", "S")
s2 = Student("Joseph2", 9, "male", "The School", "S")
s3 = Student("Joseph3", 10, "male", "The School", "S")
s = School()
s.add(s1)
s.add(s2)
s.add(s3)
print(s.search("Joseph", "name"))
print(s.search(10, "age"))
print(s.search("gender", "binary"))
print(s.search("The School", "name_of_school"))
Out:
[<__main__.Student object at 0x107c19fd0>]
[<__main__.Student object at 0x107c19ee0>]
[]
[<__main__.Student object at 0x10ab16fd0>, <__main__.Student object at 0x10ab16fa0>, <__main__.Student object at 0x10ab16ee0>]

How to print as string a parameter which is a list from class in python

I want to print all grades as a csv string for the particular Student. How can i achieve this as it prints out memory location instead:
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)
else:
pass
def __repr__(self):
return "Student name is {name} and attends year {year}".format(name=self.name, year=self.year)
pieter = Student("Pieter Bruegel the Elder",8)
class Grade:
minimum_passing = 65
def __init__(self,score):
self.score = score
pieter.add_grade(Grade(100))
pieter.add_grade(Grade(95))
pieter.add_grade(Grade(85))
print(str(pieter.grades)) #this one prints [<__main__.Grade object at 0x7fc3874d76d8>]
print(pieter)
I also added it in the __repr__ but still the same.
Give Grade a __str__ method that returns the score as a string.
class Grade:
minimum_passing = 65
def __init__(self,score):
self.score = score
def __str__(self):
return str(self.score)
Then print(pieter.grades) should print:
[100,95,85]
You can't get rid of the [] surrounding it, because that's the way lists print. You can't customize the container's printing from the elements within it. If you need to do that, you should define your own GradeList class.

Understanding Inheritance

I'm trying to understand inheritance better. In the following code, when I try to print friend.salary, it throws an AttributeError. Doesn't WorkingStudent inherit all methods of the Student class?
class Student:
def __init__(self,name,school):
self.name = name
self.school = school
self.marks = []
def average(self):
return sum(self.marks)/len(self.marks)
def friend(self,friend_name):
return Student(friend_name, self.school)
anna = Student("Anna","MIT")
friend = anna.friend("Motilal")
#print (friend.name)
#print (friend.school)
class WorkingStudent(Student):
def __init__(self,name,school,salary):
super().__init__(self,name,school)
self.salary = salary
anna = WorkingStudent("Anna","SXS",25000)
anna.friend("Greg")
anna.marks.append(50)
print friend.salary
You should modify your source code as below
class Student:
def __init__(self,name,school):
self.name = name
self.school = school
self.marks = []
def average(self):
return sum(self.marks)/len(self.marks)
def friend(self,friend_name):
return Student(friend_name, self.school)
anna = Student("Anna","MIT")
friend = anna.friend("Motilal")
#print (friend.name)
#print (friend.school)
class WorkingStudent(Student):
def __init__(self,name,school,salary):
super(WorkingStudent,self).__init__(name,school)
self.salary = salary
# anna = WorkingStudent("Anna","SXS",25000)
def friend(self,friend_name):
return WorkingStudent(friend_name, self.school, self.salary)
# You should put your code here, because as your original code
# anna is an instance of Student not WorkingStudent class
# so it and its friend don't have "salary".
anna = WorkingStudent("Anna","SXS",25000) # After this line, anna is a different variable to "anna" variable that was defined before (anna = Student("Anna","MIT"))
friend = anna.friend("Greg") # friend now is an instance of WorkingStudent class, so it have salary
anna.marks.append(50)
print(friend.salary)
Editted. So code can work now

Python: Classes that use other classes

So I have 2 files that work together using each other's classes.
I have
class Student:
"""A class to model a student with name, id and list of test grades"""
def __init__(self, name, id):
"""initializes the name and id number; sets list of grades to []"""
self.s_name = name
self.ident = id
self.tests=[]
def getID(self):
return self.ident
def get_name(self):
""" returns the student name"""
return self.s_name
def addtest(self,t):
"""adds a grade to the list of test grades """
self.tests.append(t)
def __str__(self):
"""returns the student name and the current list of grades"""
return self.s_name + " " + str(self.tests) + " "
def comp_av(self):
"""returns the average of the current set of grades or 'no grades'
if appropriate"""
if len(self.tests) > 0:
sum = 0.0
for item in self.tests:
sum = sum + item
average = float(sum)/len(self.tests)
return average
else:
return "no grades"
Which is completely done. I also have code that is from the teacher's point of view. The students are not just represented by their names but by an object of class Student. Each Student object has their name and ID number, but also a list of test scores. Right now Course has only the constructor and the __str__ method.
from LabStudentClass import *
class Course:
""" A class to model a course which contains a list of students"""
def __init__(self,teacher):
"""Sets up a class to hold and update students"""
self.students = []
self.teacher = teacher
def __str__(self):
""" prints the course by listing each student in the class"""
result = self.teacher+"'s Class\n"
for s in self.students:
name = s.get_name()
result = result + name + '\n'
return result
c = Course("Dr. Bradshaw")
#print c
def AddStudent(name, id):
student1 = Student('Mary Comtpon', '3456')
student2 = Student('Billy Jo', '2345')
student3 = Student( 'Anne lou', '1090')
print student1
print student2
print student3
My goal is to create a method AddStudent: This method gets two parameters, a student name and an ID. A new Student object is created and added to the course.
Add 3 students to your class and print out the class to test it.
However, the students aren't printing and I'm not really sure what the problem is.
Add this method to your Course class:
def addStudent(self, name, id):
student = new Student(name, id)
self.students.append(student)
Then, replace the function you wrote at the bottom with the following:
c.addStudent('Mary Comtpon', '3456')
c.addStudent('Billy Jo', '2345')
c.addStudent('Anne lou', '1090')
print c

Categories