Defining Class Methods in Python 3.43 [closed] - python-3.x

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to define a class called Student with a name, ID number, test scores, and average of test scores. When I run the program, everything works except printing the test score average after new scores have been appended to the original score list in the class. It keeps the original average of "Undefined", and I can't figure out why it's not updating.
class Student:
"""The Student class stores the first and last name of a student,
as well as all of their exam scores and overall average."""
def __init__(self, Id, first='', last=''):
"""Create a student object (e.g., Student(123654, Jane, Doe))"""
self.Id = Id
self.first_name = first
self.last_name = last
self.scores = []
self.average = 'Undefined'
def getId(self):
"""Retrieves student's Id number"""
return self.Id
def getfirst(self):
"""Retrieves student's first name"""
return self.first_name
def getlast(self):
"""Retrieves student's last name"""
return self.last_name
def getscore(self):
"""Retrieves list of student's test scores"""
return self.scores
def getaverage(self):
"""Retrieves student's average test score"""
return self.average
def add_score(self, score):
"""Updates student's list of test scores"""
self.scores.append(score)
return self.scores
def calculate_average(self):
"""Updates student's average test score using updated list of scores"""
self.average = sum(self.scores) / len(self.scores)
return self.average
def __str__(self):
"""Organizes student's information into a printable statement"""
return "ID: " + self.Id + " Name: " + self.first_name + " " + \
self.last_name + " Average Score: " + self.average
def main():
print('This program reads student data from a file, prompts the')
print('user for the total number of exams completed, and outputs ')
print('the average score for each student.')
infile = open("student_data.txt", "r")
student_list = []
num_exams = int (input('Enter the number of exams completed: '))
for line in infile:
Id, first, last = line.split()
student = Student(Id, first, last)
print('Enter scores for student', Id)
for i in range(num_exams):
score = int (input('Enter an exam score: '))
student.add_score(score)
student_list.append(student)
infile.close()
for student in student_list:
student.getscore
student.calculate_average
student.getaverage
print(student)
main()

Here is a more Pythonic class definition:
from math import nan
from statistics import mean, StatisticsError
class Student(object):
"""The Student class stores the first and last name of a student,
as well as all of their exam scores and overall average."""
def __init__(self, Id, first='', last=''):
"""Create a student object (e.g., Student(123654, Jane, Doe))"""
self.Id = Id
self.first = first
self.last = last
self.scores = []
def __repr__(self):
"""Organizes student's information into a printable statement"""
return "{0.__class__.__name__}({0.Id}, '{0.first}', '{0.last}', {0.average})".format(self)
def __str__(self):
"""Organizes student's information into a printable statement"""
return "{0.__class__.__name__}({0.Id}, '{0.first}', '{0.last}', {0.average})".format(self)
#property
def average(self):
try:
return mean(self.scores)
except StatisticsError:
return nan
def add_score(self, score):
"""Updates student's list of test scores"""
self.scores.append(score)
By using the #property decorator, self.average is a property which will calculate itself. This helps avoid the question of "has self.average been updated yet?", since all of the calculation is done by the attribute itself. Also, this way you can use nan (not-a-number) if there are no scores.

One thing that strikes me as something that needs to be addressed is that you are not calling the class methods in the final loop.
try
for student in student_list:
student.calculate_average()
print(student)
The rest of the methods are unnecessary as (I assume) you only want to print the values, and not store it in variables.

Related

Getting a value from a Class Object in Python based on User Input

so I'm in the process of learning Python, so forgive any naivety.
I'm doing some practice on Classes - and I'm making it so that when a user input their car - it looks for instantiated objects and then returns the price.
I get it to work okay for "BMW" - but when I try Ferrari - it only return the price for the BMW (20k). I'm thinking it is something not right with the price_check function part of the code.
Please could you provide some guidance here? Code below:
class Car:
car_list = []
def __init__(self, make, model, price):
self.make = make
self.model = model
self.price = price
self.car_list.append(self)
#this is the part of the code that i'm stuck with
def price_check(self):
for i in Car.car_list:
if New_Car.make == self.make:
return i.price
else:
print("Not available")
BMW = Car('BMW', '1 Series', "£20,000")
Ferrari = Car('Ferrari', 'Italia', "£90,000")
New_Car = Car(
input("What is make of your car? "), input("What is the model? "), "")
print("The cost of this car is: ", New_Car.price_check())
So essentially, I want it to return the price of the Ferrari if that's what the user typed.
Thanks in advance. And, sorry for any incorrect formatting, etc...
Okay, I agree with the comments made by #Jarvis regarding errors in your code, I would also add that in Cars init the price is a required variable and should cause an error on instantiation. In addition, in price_check, since the new_car instance has already been added to the list, price_check will also examine that entry and either find None or 0 price, so will never get to the "No Price Available" return. Here's how I would implement the Class
class Car:
car_list = []
def __init__(self, make, model, price=None): #makes providing price optional
self._make = make
self._model = model
self._price = price
Car.car_list.append(self)
#property
def make(self):
return self._make
#property
def model(self):
return self._model
#property
def price(self):
return self._price
#price.setter
def price(self, val):
self._price = val
def price_check(self):
for i in Car.car_list:
if i != self and self.make == i.make and self.model == i.model:
return i.price
return "Not available"
Two issues, first you need to append to the list not bound to your instance but the one bound to your class as a class-attribute:
def __init__(self, make, model, price):
self.make = make
self.model = model
self.price = price
# use the 'class' rather than the 'instance', you need to modify a class-attribute
Car.car_list.append(self)
Second, your issue in price check
def price_check(self):
for i in Car.car_list:
# you need to compare self's make with 'i.make' (elements in list)
if self.make == i.make:
return i.price
else:
print("Not available")

How to remove an object from list by a value

My problem is that I created a list of students with name and number. The task is now to remove a student by his number. My problem is that my code doesn't work.
Another problem is that it always shows the memory address instead of the value of the object.
Thanks in advance
class Student:
def __init__(self, name, number):
self.name = name
self.number = number
from .student import Student
class Course:
def __init__(self, name, code, credit, student_limit):
self.name = name
self.code = code
self.credit = credit
self.student_limit = student_limit
students = []
def add_student(self, new_student):
self.student = new_student
self.students.append(new_student)
print("Student added" +str(self.students))
def remove_student_by_number(self, student_number):
self.student_number = student_number
if student_number in self.students: self.students.remove(student_number)
print("Student removed" + str(self.students))
from .course import Course
class Department:
def __init__(self, name, code):
self.name = name
self.code = code
courses = []
def add_course(self, course):
self.course = course
self.courses.append(course)
print("Course added" +str(self.courses))
from python import *
def main():
alice = Student("Alice", 1336)
bob = Student("Bob", 1337)
math_dept = Department("Mathematics and Applied Mathematics", "MAM")
math_course = Course("Mathematics 1000", "MAM1000W", 1, 10)
math_dept.add_course(math_course)
math_course.add_student(bob)
math_course.add_student(alice)
math_course.remove_student_by_number(alice.number)
if __name__ == "__main__":
main()
self.students is a list of Student instance so it will print the instance's memory address if the method __str__ is not implemented (see here for example). You should try to print each property like student.name or student.number explicitly.
Anyway you are trying to find student_number in list of Student so of course it will never run the remove line. Instead use if student_number in [student.number for student in self.students] which is looking up the student's number list, not the student list itself. However in this case, you also want to remove the student with the student_number as the input so you may need to use a loop like this:
def remove_student_by_number(self, student_number):
for student in self.students:
if student.number == student_number:
print("Student removed" + str(student.name))
self.students.remove(student)
break

How to connect patient class with doctor class?

so I'm working on a problem I found online just to practice my python coding skills and I got stuck somewhere along the line. So I was trying to list all the patient name with the one of the class definition called print_list_of_patients. However, I don't know how to link the patient with the attribute so that I could just refer to the name based on the date of their appointment
I tried to combine each patient into tuples, dict but I still couldn't get what I'm looking for. Basically, I was trying to group the patient class so that every time I look at the appointment date, I can access their name and their sickness as well.
class Doctor:
def __init__(self, name):
self.name = name
self.list_of_patient = []
self.availability = []
def __str__(self):
return "Hi, this is Dr. {a}".format(a=self.name)
def add_patient(self, patient):
self.list_of_patient.
def remove_patient(self, patient):
for dates in self.availability:
if len(self.list_of_patient) == 0 and self.availability[dates]:
print("There is no patient left")
else:
self.list_of_patient.remove(patient.name)
def add_days(self, *dates):
self.availability.append(dates)
def remove_days(self, *date):
for num in range(len(self.availability)):
if date == self.availability:
self.availability.remove(date)
def print_list_of_patient(self, date):
print("Dr. {a} patient's list for {b}:\n".format(a=self.name, b=date))
class Patient:
def __init__(self, name, sickness, date_of_appointment):
self.name = name
self.sickness = sickness
def __str__(self):
return "Name: {a}\n Sickness: {b}\n\n".format(a=self.name, b=self.sickness)
def set_up_appointment(doctor, patient):
"""
set_up_appointment(doctor, patient, date)
doctor = variable name (unique ID)
patient = variable name (unique ID)
:return:
"""
doctor.add_patient(patient)
def cancel_an_appointment(doctor, patient):
"""
cancel_an_appointment(doctor, patient)
doctor = variable name (unique ID)
patient = variable name (unique ID)
:return:
"""
for names in range(len(doctor.number_of_patient)):
if patient.name == doctor.number_of_patient[names].name:
doctor.remove_patient()

How to create addPlayer() method. (Python 3)

I'm currently working on an OOP project in my CSI class in which I have to create various sports team and athlete objects as well as a method addPlayer() for adding the athletes to a roster. This is what I have so far.
class Athlete:
def __init__(self, name, number):
self.name = name
self.number = number
def __str__(self):
return "Athlete(" + self.name + ", " + self.number + ")"
def name(self):
return self.name
def number(self):
return self.number
from Athlete import *
class SportsTeam:
roster = []
def __init__(self, city, name, colors):
self.city = city
self.name = name
self.colors = colors
SportsTeam.roster = roster
def __str__(self):
return "SportsTeam(" + self.city + ", " + self.name + \
", " + str(self.colors) + ", " + ")"
def getcity(self):
return self.city
def getname(self):
return self.name
def getcolors(self):
return self.colors
def getRoster(self):
return SportsTeam.roster
def printRoster(self):
for player in roster:
print("Current Team Roster: " + str(SportsTeam.roster))
def addPlayer(self, player):
SportsTeam.roster.append(player)
return SportsTeam.roster
The thing is when I try to use the addPlayer() method I created, I get an error message telling me that list has no attribute. Not sure what needs to be added to fix this.
P.S I have only been programming for a couple of months, so I apologize if the solution is obvious
When you are dealing with classes, you have your instance variables (like self.city = city) and your class variables (like roster = []).
Instance variables are tied to an instance of the class. So if you create 2 SportsTeam objects, they each have their own city.
Class variables are a little different. They are not tied to an instance of the class; meaning, no matter how many SportsTeam objects you create, there will only be one roster variable.
To me, roster being a class variable seems a bit odd because each SportsTeam should have its own roster. However, if you are required to use class variables for you CSI class, maybe you could keep a list of all_teams and/or all_players.
Taking this into consideration:
class SportsTeam:
all_teams = []
all_players = []
def __init__(self, city, name, colors):
self.city = city
self.name = name
self.colors = colors
self.roster = []
SportsTeam.all_teams.append(self)
def __str__(self):
return "SportsTeam(" + self.city + ", " + self.name + ", " + str(self.colors) + ")"
def getCity(self):
return self.city
def getName(self):
return self.name
def getColors(self):
return self.colors
def getRoster(self):
return self.roster
def printRoster(self):
# the for loop was unnecessary
print("Current Team Roster:", str(self.roster))
def addPlayer(self, player):
SportsTeam.all_players.append(player)
self.roster.append(player)
return self.roster
If you would like to keep roster as a class variable, leave a comment and I can help you adjust the code to accommodate for this.

Sorting a dictionary that contains a class holding 5 variable by one of the class variables

I have a dictionary that contains keys that are made from a class containing 5 variables. I want to sort this dictionary by one of the class vars.
here is what i currently have
class Player:
def __init__(self,name,wins,losses,ties,winpercent):
self.__name = name
self.__wins = wins
self.__losses = losses
self.__ties = ties
self.__winpercent = winpercent
# mutators
def setname(self,name):
self.__name = name
def setwins(self,wins):
self.__wins = wins
def setlosses(self,losses):
self.__losses = losses
def setties(self,ties):
self.__ties = ties
def setwinpercent(self,winpercent):
self.__winpercent = winpercent
# accessors
def getname(self):
return self.__name
def getwins(self):
return self.__wins
def getlosses(self):
return self.__losses
def getties(self):
return self.__ties
def getwinpercent(self):
return self.__winpercent
def displayHighScores(self):
print("\n"," "*2,self.__name," "*(24-len(self.__name)),self.__wins)
def displayplayers(self):
print(self.__name)
I store Players like this:
def addplayer(players):
newName = input("\nEnter new Player name or 9 to quit: ")
wins = "0"
losses = "0"
ties = "0"
winpercent = "0"
if not newName:
print("\nNo name detected try again")
addplayer(players)
elif newName == '9':
print("\nReturning to Options menu")
else:
players[newName] = Player(newName,wins,losses,ties,winpercent)
saveData(players)
return players
Finally i am working on a sorted hi scores list. right now i can print my dictionary unsorted like this:
def printhiscores(players):
print("\n"," "*13,"HiScores")
print(" "*3,"Name"," "*20,"Wins")
if len(players) == 0:
print("\nNo current Players in memory.")
else:
for x in players.keys():
players[x].displayHighScores()
DisplayHighScores () being a part of the class object.
I have been reading on dictionary sorting using
OrderedDict(sorted(players.items(), key=itemgetter(1)))
but this returns edit:TypeError: '<' not supported between instances of 'Player' and 'Player'
Again I am looking to sort my dictionary of players by their win attribute and then print this new order to a high score screen. Any help would be greatly appreciated. I will post if i make any more progress on my own on this.
Your Player instances are not orderable however, as they don't implement comparison methods:
TypeError: '<' not supported between instances of 'Player' and 'Player'
If you wanted to sort them by the value returned, say, wins, then just access that information instead of just returning the value:
OrderedDict(sorted(players.items(), key=lambda kv: kv[1].getwins()))
Otherwise, give your Player class rich comparison methods; methods by which to determine when one instance should be sorted before or after another. You'll also need an equality test. It's easier to just implement support for < (lower then) and equality, then use the #functools.total_ordering decorator to provide the rest:
from functools import total_ordering
#total_ordering
class Player:
def __lt__(self, other):
if not isinstance(other, Player):
return NotImplemented
return self.__wins < other.__wins
def __eq__(self, other):
if not isinstance(other, Player):
return NotImplemented
return self.__wins == other.__wins
The above makes two Player instances equal when their wins are equal, and orders them by that attribute. You'll need to adjust this for your application as needed.

Resources