Where does this (student) append come from - python

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

Related

How to edit a instance variable?

I'm new to python and as I was doing an assignment for class, I got stuck using init method.
class Customer(object):
def __init__(self, number, name):
self.name = name
self.number = number
self.orders = []
def addorder(self, order):
self.orders.extend(order)
return self.orders
def __str__(self):
return str(self.orders)
Customer('308','John').addorder((1,2,3,4))
print(Customer('308','John'))
The output is an empty list [].
I want the output to be [1,2,3,4]
What am I doing wrong here?
The issue is that you have two Customer objects. I.e. your print line:
print(Customer('308','John'))
Is creating a new Customer object with a number of '308' and a name of 'John'. It's completely unrelated to the customer on the previous line.
To fix this, you should assign your first object to a variable (think of it like a handle, that lets you access the object), and then print that:
john = Customer('308','John')
john.addorder((1,2,3,4))
print(john)
You're creating two instances of the class
class Customer(object):
def __init__(self, number, name):
self.name = name
self.number = number
self.orders = []
def addorder(self, order):
self.orders.extend(order)
return self.orders
def __str__(self):
return str(self.orders)
customer = Customer('308','John')
customer.addorder((1,2,3,4))
print(customer)
Keep in mind that each time you "call" a class, you instantiate a new object (this is why in many languages other than Python, this actually requires the keyword new). So, in your example, you're instantiating two different objects (that don't share their properties). Instead, you should save them in a variable:
customer = Customer("308", "John")
customer.addorder((1, 2, 3, 4))
print(customer)

Class within a class (as attribute) to call a method of the class that contains it

I am in the situation where I need a class that is within another (as an attribute) to communicate with the class that contains it, however, I cannot wrap my head around how to do it.
Take this situation as an example: There is a class HighSchoolClass that contains a list of Students that belong to that class, and HighSchoolClass has a method foo rearranging how the students are sited or whatever. But then, each student has the capability of asking if a rearranging can be made. So it would need to call the method for rearranging the class.
# Singelton
class HighSchoolClass:
def __init__(self):
self.list_of_students = # A list of instances of Student
self.profesor = ...
def rearrange_class():
# do something
class Student:
def ask_for_rearrange():
# Needs to call rearrange_class() of the class he is in.
Is there any way of do this (ideally just calling it somehow)? Mind that rearrange_class() is not static. If it helps, the HighSchoolClass would be a singelton.
Typically, you would explicitly give each Student a reference to the HighSchoolClass that they belong to. A simple example might look like
class Student:
def __init__(self):
self.class_ = None
def add_class(self, class_):
self.class_ = class_
class HighSchoolClass:
def __init__(self):
self.list_of_students = []
def add_student(self, student):
self.list_of_students.append(student)
class Registrar:
def add_student_to_class(self, student, class_):
class_.add_student(student)
student.add_class(class_)
Note the use of a third class to both the student and the class. Otherwise, it's not obvious whether a student should be responsible for updating each class they join, or whether each class should update their students.
the_class = HighSchoolClass()
s1 = Student()
s2 = Student()
r = Registrar()
r.add_student_to_class(s1, the_class)
r.add_student_to_class(s2, the_class)
Now, each class and student has a reference to the other to be used as needed.

Having a list in a python class with a different name?

Here is the task: Write a class called LineUp.This class should contain
one (private) field (called acts) to store up to 30 acts. This field should be initialised in the constructor.
A method add_act that takes an Act (keep in mind I've written code above this with 'Act' and that's all fine) as an argument and adds it to acts if there are fewer than 30 acts already, otherwise a message “The festival is full!” should be printed,
add a method toString or str which produces a nice string with full line-up,
add a method print which prints a nice string with the full line-up.
I'm assuming that the first point is asking for a list. I think I've found a way to have a list in a class, but it has the same name (LineUp, as opposed to 'acts'). Here's what I have
class LineUp(list):
def __init__(self):
self.acts = []
def add_act():
if len(acts) >= 30:
print("The festival is full!")
else:
acts.append(Act)
def __str__(self):
string = "LineUp" + str(LineUp)
def println(self):
print(__str__(self))
Thanks in advance! Keep in mind this is my first draft.
EDIT: should I actually use a dictionary, not a list? Know that in another file I'm testing this code
You don't nee to inherit from list or get acts as parameter. To create a list for the class use self.acts in the constructor. You should also add __repr__
class LineUp:
def __init__(self):
self.acts = []
def add_act(self, act):
if len(self.acts) >= 30:
print("The festival is full!")
else:
self.acts.append(act)
def __repr__(self):
return f'LineUp{str(LineUp)}'
def __str__(self):
return f'LineUp{str(LineUp)}'
def println(self):
print(f'LineUp acts:{[act for act in self.acts]}')
Notice that str(LineUp) will return something like <class 'ExampleTest.LineUp'>, you might want to edit it.

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

Print method output as a string, not as a function

In my Student subclass below, I am calculating average GPA from manually inputted grades stored in the self.courses dict attribute as {course:grade}.
The user should be able to enter in the console >>>print(fred.gpa),given fred is a proper Student instance with grades in self.courses, and should get 3.8 (for example) printed to the console.
However, 3.8 does not print to console, rather <bound method Student.gpa of <college.Student object at 0x7ff55e122ad0>>
I understand that this is the result of printing a function, but I want to print just a number using just print(fred.gpa) and not fred.gpa()
Does this mean I have to convert the output of gpa.Student into a string?
Here is my code for ref:
def __init__(self, name, cid, email):
self.courses = {}
super().__init__(name, cid, email)
def add_course(self, course):
if course in self.courses:
# duplicate courses not allowed
raise ValueError
print("student is already registered for this course")
else:
self.courses.update({course:0})
return self
def update_grade(self, course, grade):
if course not in self.courses:
# student must be registered in class to receive grade
raise ValueError
print("student is not registered for this course")
else:
self.courses[course] = float(grade)
return self
def gpa(self):
grades = list(self.courses.values())
totGPA = sum(grades)/len(grades)
return str(totGPA)
What you need is something that will let you implement something as a method, but access it as a non-method attribute. That turns out to be quite easy - it's called a property, and it works like this:
class Student:
#property
def gpa(self):
# Rest of the implementation, unchanged
Ta-da!
Note that you can fix up your implementation of gpa a little: sum can take any iterable (it doesn't have to be a list), and dicts (and their keys, values and items views) have a length, so you can do:
#property
def gpa(self):
return sum(self.courses.values())/len(self.courses)
I've omitted your call to str, since it seems from your question that that was a first attempt to fix your problem. You could reinstate it if you need it there for some other reason.

Categories