Printing from different class - python

I've searched for similar questions, and have not found anything.
Apparently because my question is pretty basic, yet I find it hard to understand.
I have a class named Student. In this class I get a name of student, and his grades then calculate his average grade. That one was easy, of course.
Here's what I've succeed so far:
class Student:
def __init__(self, name, grades_list):
self.name = name
self.grades_list = grades_list
def get_grade_avg(self):
avg = sum(self.grades_list) / len(self.grades_list)
return avg
def get_name(self):
return self.name
From the previous part I have:
john = Student("John", [100, 90 ,95])
Now I need to answer the following qeustion:
Write a class ClassRoom which has a constructor that receives a list of type Student, and saves this list to a member. The following should create a class room:
class_room = ClassRoom([John])
Implement class ClassRoom such that when calling print(class_room) on a ClassRoom type prints a list of tuples of student name and student grade average, in that order.
Calling print(class_room) should output:
[('John', 95)]
How do I do it?
I'm very new to OOP and have no idea even how to start.
Thank you!

You can do it like this:
class Student:
...
def __repr__(self):
return str((self.name, self.get_grade_avg()))
class ClassRoom:
def __init__(self, students):
self.students = students
def __str__(self):
return str(self.students)
john = Student("John", [100, 90 ,95])
mike = Student("Mike", [90, 80, 85])
c = ClassRoom([john, mike])
print(c)
# [('John', 95.0), ('Mike', 85.0)]
print(c)
When you call print on some object its __str__ method is invoked and if it is not defined __repr__ is called. By default __repr__ of some object is something like this: <__main__.Student object at 0x7f4b35a3a630>
In the above code a Student knows how to show itself, (name, avg), so you can print it if you like: print(john)
And for your ClassRoom, you just need to override __str__ to show the student list. Since every student knows how to show itself, it will do the job.

you need to add str() function to both class and student classes. str() if class should iterate over the list of students and print them on by one.

Related

Add a result from class object to another class in python

Hi everyone I am new to Python and currently, I am learning about class.
I have two classes. 1 class has a result of the student's name and address.
class Student:
def __init__(self, name, address, units = []):
self.name=name
self.addrress = address
self.units=units
Now I have another class which is School. The class can store the Students by adding from Student class, count how many students are on the list, also delete the student data.
class School:
def __init__(self):
self.school = []
def __len__(self):
length(self.school)
def admission(self, student):
self.school.append(student)
def delete_student(self, name, address):
self.name=name
self.organisation=organisation
for i in range(0,len(self.school)):
if self.name.lower() == name.lower() and self.address.lower() == address.lower():
del self.school[i]
else:
print("The student you input is not exist")
I want to put all the students that I define from class Student into school.
When I do something like this
a = Student("Batman", "Gotham", ["Science","Chemi"])
b = Student("Harry", "Hogwarts", ["Magic"])
School.admission(a)
There are error that said admission() missing 1 required positional argument: 'student'
How to figure this out? Maybe I did wrong in calling the argument. Help will be appreciated.
Thank you.
=================================================
School is the class, but you defined admission as an instance method. So you need an instance of School that you can admit students to:
school = School()
school.admission(a)
Basically admission is an instance method, so you should define your school instance, then add students:
school1 = School()
school1.admission(a)
people are saying that -
school1 = School()
school1.admission(a)
this resolves issue.
But try calling the list school from school1 and it will contain the student as class object like this
print(school1.school)
#output-
[<__main__.Student object at xyz...>]
So you should change your code like this...
def admission(self,student):
self.school.append(student.name)
after changing this part of your code as how i metioned above let's try calling list now.
a=Student('harry','hogwarts',['magic','spells'])
school1=School()
school1.admission(a)
print(school1.school)
#output-
['harry']
sorry for bad variable names.
please upvote.

Where does this (student) append come from

class Student:
def __init__(self,name,age,grade): #giving the attributes
self.name=name
self.age=age
self.grade=grade
def get_grade(self):
return self.grade
class Course:
def __init__(self,lesson,max_student):#giving attributes
self.lesson=lesson
self.max_student=max_student
self.students=[]
def add_student(self,student):
if len(self.students)<self.max_student:
self.students.append(student) #append(student) from where
#I don't get where the append(student) get the name from.
#As above code did't use student.
return True
return False
s1=Student('Tim',19,95) #Naming the student
s2=Student('bill',19,75)
s3=Student('jill',19,65)
course1=Course('Math',2)
course1.add_student(s1) #Adding the Student to a list by appending
course1.add_student(s2)
print(course1.students[0].name)
#Will give Tim but how do i print them all at once
#instead of multiple print maybe like a [0:1] but got error
The append method is part of Python. It's part of the list class, so all lists have this method (among others). Check the docs. You set self.students to an empty list in the line self.students = [].
The student variable comes from the argument to add_student, as you specified here: def add_student(self,student). So, when you call course1.add_student(s1), the s1 will be student inside the method (because for class methods, the first argument self is always the class instance itself and doesn't have to be specified in the call).

How to call a class in a function Python

I'm a complete amateur, and trying to work out how to write a function that takes a list of objects, and returns a list of the names of said objects (based on whether they pass if statement). This is the class I've written from help of tutorials:
class Student:
passmark=50
def __init__(self,name,mark):
self.name=name
self.mark=mark
def passes(self):
return self.mark > Student.passmark
So from now I'm assuming I make a list of objects, say:
students = []
Though this list is just a brand new list, which was necessary sure but how would I link it to the class? From this point I want to find out which students have failed, and return them and also where I am confused:
def failed(list):
for student in Students:
if passmark > self.mark:
return list
Is all I can muster, sorry I've just gotten to classes and calling classes is quite confusing for me. The above code doesn't reference the class at all, and I really am confused on how to do so. I've no syntax errors or anything, I think my logic is fatally flawed.
You want to take all the student from the students list. So use that in the for loop. Also, you correctly encapsulated the logic of pass/fail criteria in a method, so use that.
Here is the code I think will do want you want:
def failed(list_of_students):
failed_students = []
for student in list_of_students:
if not student.passes():
failed_students.append(student.name)
return failed_students
A more advanced way of doing it is by using list comprehension:
def failed(list_of_students):
return [student for student in list_of_students if not student.passes()]
It is more pythonic, but my be harder to understand for a beginner with a C or Java background.
You can use a list comprehension like this:
def failed(list):
return [student.name for student in students if not student.passes()]
Try this code. Using list comprehension to return results. It's a very powerful python tool.
class Student:
passmark = 50
def __init__(self, name, mark):
self.name=name
self.mark=mark
def passes(self):
return self.mark > Student.passmark
def __repr__(self):
return '{} {}'.format(self.name, self.mark)
def failed(students_list):
return [student for student in students_list if student.mark < Student.passmark]
Given a Student class like you defined:
class Student:
passmark=50
def __init__(self,name,mark):
self.name=name
self.mark=mark
def passes(self):
return self.mark > Student.passmark
You could instantiate a list of students with:
students = [Student("John", 49), Student("Mary", 75)]
It looks like you are also trying to define a function that will return a list of all the failed students; you could do something like this:
def failed(student_list):
return [x for x in student_list if not x.passes()]
mark_to_pass = 50
#Approach one
class Student:
def __init__(self, student_name, student_mark):
self.name = student_name
self.mark = student_mark
self.pass_mark = self.calculate_passing_mark(mark_to_pass)
def calculate_passing_mark(self, mark_to_pass):
if self.mark >= mark_to_pass:
return True
return False
if __name__ == '__main__':
example_student = Student("Swanson", 75)
print(example_student.pass_mark)
With this approach every time a student object is created it will tell create a field telling you that student has passed. When working with lists such as a list of student objects you need to add the student to your list. Example
students = []
students.append(example_student)
Now you can look through your student list by doing
for student in students:
print(student.pass_mark) # or do some other logic passed on who passed or failed. Or even here you dont need to create pass_mark object you can just check if student.mark > pass_mark
I'm assuming that failed isn't a member function of the class Student. The below code should work for what you are trying to do.
class Student:
passmark=50
def __init__(self,name,mark):
self.name=name
self.mark=mark
def passes(self):
return self.mark > Student.passmark
students = [Student("tom",40),Student("joe",70)]
def failed(listofStudents):
listofStudentsThatFail = []
for student in listofStudents:
if not student.passes():
listofStudentsThatFail.append(student)
return listofStudentsThatFail
for s in failed(students):
print s.name
The ouput when you run the code is:
tom

Iterate through instantiated objects of a class

Isit possible to loop through the objects of class person and extract the attributes?
so for e.g. from below code after looping the output would be for each object as such
Object mike, name-Mike, age-20
class Person(object):
def__init__(self,name,age):
self.name = name
self.age = age
mike = Person('Mike',20)
john = Person('John',20)
jack = Person('Jack',20)
adam = Person('Adam',20)
Thanks
Python classes don't automatically track all their instances. You can use a class attribute to track them yourself if you need to:
class Person(object):
people = []
def __init__(self, name, age):
self.name = name
self.age = age
self.people.append(self)
Even better would be to have a separate object that tracked people. The Person.people attribute here is a single global value for the process, which can limit the usability and testability of the class.
To loop the attributes of a given instance, I think you're looking for the builtin function vars:
>>> mike = Person('Mike', 20)
>>> vars(mike)
{'age': 20, 'name': 'Mike'}
To loop through all instances of a given class is not possible, unless you add some code to maintain the list of instances yourself.
if my understanding is right, you are asking about looping the class person
then it can be done like this.
class person(object):
def __init__(self,name,age):
self.name=name
self.age=age
for name,age in {'mike':20,'john':20,'jack':20}.iteritems():
p = person(name,age)
print ('I am %s my age is %d' %(p.name,p.age))
## answer
I am mike my age is 20
I am john my age is 20
I am jack my age is 20

how to avoid staticmethod in my Python sample

I want to store sorted instances of Student class, into Students class. And I am using staticmethod in Students class for sorting. I could be wrong, but the design seems a bit ugly and want to avoid using static method (the most ideal way in my mind is using a class method in class Student which returns student ID, and use this method for sorting, but it seems not an easier way to set a class method of class Student in class Students for sorting), if there is a better design, appreciate if you could share,
class Student:
def __init__(self, id):
self.id = id
class Students:
def __init__(self, students):
self.sortedStudents = sorted(students, key=Students.getStudentID)
#staticmethod
def getStudentID(student):
return student.id
def dumpAllStudents(self):
for student in self.sortedStudents:
print student.id
students = []
students.append(Student(100))
students.append(Student(90))
students.append(Student(80))
allStudents = Students(students)
allStudents.dumpAllStudents()
thanks in advance,
Lin
Using operator.attrgetter:
import operator
...
def __init__(self, students):
self.sortedStudents = sorted(students, key=operator.attrgetter('id'))
operator.attrgetter('id') returns a callable that returns the attribute id from the operand. So it can be used instead of the static method or lambda.
You could use a lambda expression instead:
class Students:
def __init__(self, students):
self.sortedStudents = sorted(students, key=lambda s: s.id)
...
Whether you want to do this or have your Student class itself be comparable (see tzaman's answer) depends a bit on the rest of your code and your intent. If you need an order on students elsewhere, include the ordering in the Student class. If you only want them ordered inside your Students class, use my approach.
From an OOP design perspective, I wouldn't consider students to be ordered in general, but that's for you to decide (and may in the end be a matter of convenience).
If your objective is just to sort Student's instance based on its id, you don't need another function or method for that. You can achieve this using lambda expression.
class Student:
def __init__(self, id):
self.id = id
class Students:
def __init__(self, students):
self.sortedStudents = sorted(students, key=lambda stud: stud.id)
def dumpAllStudents(self):
for student in self.sortedStudents:
print student.id
students = []
students.append(Student(100))
students.append(Student(90))
students.append(Student(80))
allStudents = Students(students)
allStudents.dumpAllStudents()

Categories