Python object creating a group with 3 members of aggregation relationship - python

I had an assignment to create a python code using class to create a group with 3 members (aggregation relationship). This is my code so far:
class Member:
def __init__(self,name,age):
self.name = name
self.age = age
def getInfo(self):
memberInfo = "Name: " + str(self.name) + "." + "Age: " + str(self.age)
return memberInfo
class Group:
def __init__(self,name):
self.name = name
self.memlist = []
def addMember(self,member):
self.memlist.append(member)
def getInfo(self):
info = "Member List: \n"
for i in range(len(self.memlist)):
info += self.memlist[i].getInfo() + "\n"
print(info)
break
mem1 = Member("Chi",20)
mem2 = Member("Bach",7)
mem3 = Member("Gen", 22)
group1 = Group("Siblings")
group1.addMember(mem1)
group1.addMember(mem2)
print(group1.getInfo())
print(mem2.getInfo())
print(group1.memList)
But it has shown an error: AttributeError: 'Group' object has no attribute 'memList'. Is there anything I can do to fix this?

I wrote little function for listing members and their ages.
class member:
def __init__(self, name, age):
self.name = name
self.age = age
def member_Info(self):
memberInfo = f"Name: {str(self.name)}-->Age: {str(self.age)}"
return memberInfo
class Group:
def __init__(self, name):
self.name = name
self.memlist = []
def addMember(self, name):
self.memlist.append(name)
def getInfo(self):
for i in range(len(self.memlist)):
info = self.memlist[i].member_Info() + "\n"
print(info)
This all_members function is basically getting the information stored in the member class and return to list. I print using memlist in Group but it didn't work out so I made a new list using all_member function and get information from memlist in group1 with the code that you used for getting information in memlist at group1.getInfo .
def all_members():
all_mems = []
for i in range(len(group1.memlist)):
all_mems.append(group1.memlist[i].member_Info())
print(all_mems)
mem1 = member("Chi", "20")
mem2 = member("Bach", "7")
mem3 = member("Gen", "22")
group1 = Group("Siblings")
group1.addMember(mem1)
group1.addMember(mem2)
group1.addMember(mem3)
print(group1.getInfo())
print(mem2.member_Info() + "\n")
print(all_members())
I guess this isn't the best answer you can get but I think it will work and also I learn many things while trying to correct it so thank you for posting that.

change
print(group1.memList)
to
print(group1.memlist)

Related

How to call object of class by input?

I am generating a class of persons and want to get information about a certain person by input. I would like to use the str funtction because I am trying to understand it better. My Idea goes as follows:
class Person:
__init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
__str__(self):
return "The persons full name is:" + f_name + l_name
person1 = Person(Peter, Punk)
person2 = Person(Mia, Munch)
person = input("What persons full name would you like to know?")
print(person) #I am aware that this just fills in the string saved in person, but how do I connect it to the variable?
another idea was to do it as follows:
#class stays the same except:
__init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
list.append(self)
#and then for the main:
list = []
person1 = Person(Peter, Punk)
person2 = Person(Mia, Munch)
person = input("What persons full name would you like to know?")
index = list(person)
print(list[index])
Thankful for any edvice since I am obviously new to Python :D
I think OP has some concept problems here which this answer may go some way to help with.
Start by building a robust class definition. Simple in this case as there are just 2 attributes. Note the use of setters, getters and str, repr and eq dunder overrides.
A small function that checks if a given Person can be found in a list of Persons and reports accordingly.
Create a list with 2 different Person instances
Create another Person that is known not to match anything already in the list.
Run check()
Modify the 'standalone' Person to make it equivalent to something previously constructed.
Run check()
class Person:
def __init__(self, forename, surname):
self._forename = forename
self._surname = surname
#property
def forename(self):
return self._forename
#forename.setter
def forename(self, forename):
self._forename = forename
#property
def surname(self):
return self._surname
#surname.setter
def surname(self, surname):
self._surname = surname
def __str__(self):
return f'{self.forename} {self.surname}'
def __repr__(self):
return f'{self.forename=} {self.surname=}'
def __eq__(self, other):
if isinstance(other, type(self)):
return self.forename == other.forename and self.surname == other.surname
return False
def check(list_, p):
if p in list_:
print(f'Found {p}')
else:
print(f'Could not find {p}')
plist = [Person('Pete', 'Piper'), Person('Joe', 'Jones')]
person = Person('Pete', 'Jones')
check(plist, person)
person.surname = 'Piper'
check(plist, person)
Output:
Could not find Pete Jones
Found Pete Piper
You probably want a mapping between a name and an object. This is what Python's dict dictionary structure is for:
people = {} # an empty dictionary
people[f'{person1.f_name} {person1.l_name}'] = person1
people[f'{person2.f_name} {person2.l_name}'] = person2
This is creating a string of the first and last name.
You can then lookup the Person object using the full name:
print(people['Peter Punk'])
You could do this with list comprehension like so (also allowing multiple people to have the same first name)
class Person:
__init__(self, f_name, l_name):
self.f_name = f_name
self.l_name = l_name
__str__(self):
return "The persons full name is:" + f_name + l_name
personList= []
personList.append(Person(Peter, Punk))
personList.append(Person(Mia, Munch))
personName = input("What persons full name would you like to know?")
print([str(person) for person in personList if person.f_name == personName])

I dont know where I'm going wrong trying to create an object in a subclass through inputs

I've tried many different things so it's a little all over the place, please help
I've been able to make the first class and then in a different file create some objects for it, but for this subclass I need to use user input and I just can't figure it out.
I have made it so the shift input has to be a 1 or 2 for a day or night shift, I just don't have the knowledge for this.
class Employee:
def __init__(self, name, id, dept, title):
self.__name = name
self.__id = id
self.__dept = dept
self.__title = title
def get_name(self):
return self.__name
def get_id(self):
return self.__id
def get_dept(self):
return self.__dept
def get_title(self):
return self.__title
def __str__(self):
result = ""
result += "Name: " + self.get_name() + "\tID Number: " + str(self.get_id()) + \
"\tDepartment: " + self.get_dept() + "\tJob Title:" + self.get_title()
return result
class ShiftEmployee(Employee):
def __init__(self, name, id, dept, title, shift, pay):
Employee.__init__(self, name, id, dept, title)
self.__shift = shift
self.__pay = pay
#classmethod
def inputs(self):
self.__name = input("Enter name: ")
self.__id = input("Enter ID number: ")
self.__dept = input("Enter department: ")
self.__title = input("Enter Jobe title: ")
self.__shift = input("Enter shift: ")
self.__pay = input("Enter hourly pay: ")
#set_shift(self, shift):
#self.__shift = shift
#def set_pay(self, pay):
#self.__pay = pay
def get_shift(self, shift):
if self.__shift == 1:
return "Day"
elif self.__shift == 0:
return "Night"
else:
return "Invalid entry"
def get_pay(self, pay):
return self.__pay
def __str__(self):
result = ""
#result += Employee.__str__(self)
result += "Name: " + self.get_name(ShiftEmployee) + "\tID Number: " + str(self.get_id(ShiftEmployee)) + \
"\tDepartment: " + self.get_dept(ShiftEmployee) + "\tJob Title:" + self.get_title(ShiftEmployee) + \
"\tShift: " + self.get_shift(ShiftEmployee) + "\tHourly Pay: " + str(self.get_pay(ShiftEmployee))
return result
shift_emp = ShiftEmployee
shift_emp.inputs()
print(shift_emp.__str__(ShiftEmployee))
Don't use a classmethod because
A class method is a method that’s shared among all objects.
Though python itself does not force this behavior, your use of self in the inputs definition indicates that you are not doing what you think. the parameter is traditionally named cls in #classmethod-annotated methods, because the object you're referring to inside the body is not an instance of the class, but the class object itself. This means if you have multiple ShiftEmployee objects, they're going to be writing their data to the same variables. This is not what you want to happen.
you are not instantiating a ShiftEmployee object with shift_emp = ShiftEmployee, but rather assigning the class to the variable shift_emp, which is not what you want to do. so if you remove the #classmethod annotation, I think what you want is
shift_emp = ShiftEmployee() # __init__ gets called when you use this constructor invocation
shift_emp.inputs()
print(shift_emp)
Your __str__ methods don't make a lot of sense. You are passing the class object to each getter, which doesn't seem like it's what you'd want to do. The class object defines the class, what you want are the instances of the class. It's an important, if initially confusing distinction. Posting the error you get would help, but here's what I would expect the methods to look like. I'm not using the getters, because this is internal access, but you can use them instead of directly referring to the state variables if you prefer.
# Employee
def __str__(self):
return f"Name: {self.__name} ID Number: {self.__id} Department: {self.__dept} Job Title: {self.__title}"
# ShiftEmployee
def __str__(self):
return super(ShiftEmployee, self).__str__() + f" Shift: {self.__shift} Hourly Pay: {self.__pay}"
So what's going on here? For one thing, we use format strings because they are easier to work with and exactly the thing you wanted. Then we're using the superclass (Employee) to provide the shared functionality, and using the descendent class to enrich with the ShiftEmployee-only data. I skipped the accessor methods because they're redundant when accessing "private" data from inside the class members. Note that this won't quite do what you expect, either, w.r.t. the shift value that gets printed -- it's going to print the int, not "Night" or "Day". This is where your accessor method comes into play, except that your accessor has an extraneous parameter, shift. So you'd have to remove that value.
Please use the following way to initialize the class and printing the class,
shift_emp = ShiftEmployee() # Added Parenthesis
shift_emp.inputs()
print(str(shift_emp)) # Pass class object to inbuilt str() method to get output from __str__() method from class

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>]

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

Unbound Error Python Class

I have researched everywhere and although I find the same concepts, I cannot seem to find an answer to my error.
I did not post before because my account info was forgotten on stack, but I have grown very frustrated with this beginner's error.
class Person(object):
def __init__(self, name, phone):
self.name = name
self.phone = phone
class Employee(Person):
total_salary = 0
#staticmethod
def total_salary(self, salary):
return total_salary
def __init__(self, name, phone, salary):
self.name = name
self.phone = phone
self.salary = salary
class Student(Person):
def __init__(self, name, phone, gpa):
self.gpa = gpa
self.name = name
self.phone = phone
def __str__(self):
reply = ""
reply = "Person " + self.name + " has phone " + self.phone + "\n" + " and is a Student with gpa " + str(self.gpa)
return reply
class Professor(Employee):
def __init__(self, name, phone, salary, clas_teach):
self.clas_teach = clas_teach
self.name = name
self.phone = phone
self.salary = salary
def __str__(self):
reply = ""
reply = "Person " + self.name + " has phone " + self.phone + "\n" + " and is an Employee with salary " + str(self.salary) + "\n"
reply += " and is a Professor assigned to class " + self.clas_teach
return reply
class Staff(Employee):
def __init__(self, name, phone, salary, position):
self.position = position
self.name = name
self.phone = phone
self.salary = salary
def __str__(self):
reply = ""
reply = "Person " + self.name + " has phone " + self.phone + "\n" + " and is an Employee with salary " + str(self.salary) + "\n"
reply += " and is Staff with title " + self.position
return reply
# Create a list of people
People = [ Student("Sandy", "326-8324", 3.65), Student("Jordan", "632-7434", 3.1), \
Professor("Leslie", "985-2363", 50000.00, "Info 501"), \
Staff("Alex", "743-4638", 25000.00, "Editor") ]
# display information about our people
print "These are the people in the university:"
for person in People:
print person
# display the total salaries of all our employees and average GPA
# of all of our students
print
print "Our total university payroll budget is: " + str(Employee.total_salary)
print "Our average student GPA is: " + str(Student.mean_gpa())
Your main misunderstanding is how classes work. In your code, you are calling classes rather than instances of classes:
print "Our total university payroll budget is: " + str(Employee.total_salary)
print "Our average student GPA is: " + str(Student.mean_gpa())
The key thing here is:
Employee.total_salary
Instead you should be doing something like this:
leslie = Professor("Leslie", "985-2363", 50000.00, "Info 501")
print "Leslie's Salary: " + str(leslie.salary)
For this specific case, you want the total payroll, which is the sum of all employee salaries. You need a collection of employees somewhere.
def University():
def __init__(self):
self.employees[]
def add_employee(self, employee):
self.employees.append(employee)
def get_total_payroll(self):
total = 0
for employee in self.employees:
total += employee.salary
return total
then use an instance of that class:
university = University()
university.add_employee(Professor("Leslie", "985-2363", 50000.00, "Info 501"))
university.add_employee(Staff("Alex", "743-4638", 25000.00, "Editor"))
print "Total payroll: " + str(university.get_total_payroll())
Obviously, there are a lot more adjustments you need to make, like sorting betweeen employees and students, etc. But hopefully this is enough to get you started.
There are problems with your overall design that have been covered in other answers, so I will just try to explain why your current code is not working:
You have created a class attribute named total_salary, and then shadowed it with a method of the same name.
You are using a static method, when you need to use a class method.
You need to call total_salary as a method in order to return its value.
These problems can be fixed like this:
class Employee(Person):
_total_salary = 0
#classmethod
def total_salary(cls):
return cls._total_salary
...
print "Our total university payroll budget is: " + str(Employee.total_salary())
But note that the code will still raise an AttributeError, because you are trying to call Student.mean_gpa, which hasn't been defined yet.
Your class Employee has an attribute AND a method with the same name. Calling Employee.total_salary will return the function because in the MRO it's replacing the attribute.
Change:
class Employee(Person):
total_salary = 0
to
class Employee(Person):
total_salary_value = 0
Your staticmethod total_salary in Employee is returning a variable that doesn't exist(because it's looking only in the method scope), you should return the Employee.total_salary_value. Like so:
#staticmethod
def total_salary():
return Employee.total_salary_value
In the __init__ of Employee you are not instantiating the Person that you are inheriting (the same thing in Student(inheriting Person), Professor and Staff(both inheriting Employee)
Use either:
Person.__init__(self,name,phone)
or
super(Employee, self).__init__(name, phone)
Still in the init, you are not adding the salary to the total_salary_value
add this:
Employee.total_salary_value += self.salary
Also, there's no need to use self.name and self.phone in the Student, because Person already has this attribute. (The same for that and other variables in Professor and Staff)
And lastly, Student doesn't have a method called mean_gpa. You have to implement it.
Here's the code:
class Person(object):
def __init__(self, name, phone):
self.name = name
self.phone = phone
class Employee(Person):
total_salary_value = 0
#classmethod
def total_salary(cls):
return cls.total_salary_value
def __init__(self, name, phone, salary):
Person.__init__(self,name,phone)
self.salary = salary
Employee.total_salary_value += self.salary
class Student(Person):
all_gpa = []
def __init__(self, name, phone, gpa):
Person.__init__(self,name,phone)
self.gpa = gpa
Student.all_gpa.append(self.gpa)
def __str__(self):
return "Person {0} has phone {1} and is a Student with gpa {2}".format(self.name,self.phone,self.gpa)
#classmethod
def mean_gpa(cls):
return sum(cls.all_gpa)/len(cls.all_gpa)
class Professor(Employee):
def __init__(self, name, phone, salary, clas_teach):
Employee.__init__(self,name,phone,salary)
self.clas_teach = clas_teach
def __str__(self):
return "Person {0} has phone {1} and is an Employee with salary {2}\n" \
"and is a Professor assigned to class {3}".format(self.name,self.phone,self.salary,self.clas_teach)
class Staff(Employee):
def __init__(self, name, phone, salary, position):
Employee.__init__(self, name, phone, salary)
self.position = position
def __str__(self):
return "Person {0} has phone {1} and is an Employee with salary {2}\n" \
"and is Staff with title {3}".format(self.name, self.phone, self.salary, self.position)
# Create a list of people
People = [ Student("Sandy", "326-8324", 3.65),
Student("Jordan", "632-7434", 3.1),
Professor("Leslie", "985-2363", 50000.00, "Info 501"),
Staff("Alex", "743-4638", 25000.00, "Editor") ]
# display information about our people
print "These are the people in the university:"
for person in People:
print person
# display the total salaries of all our employees and average GPA
# of all of our students
print
print "Our total university payroll budget is: " + str(Employee.total_salary())
print "Our average student GPA is: " + str(Student.mean_gpa())
EDIT:
As #ekhumoro said, it's better to use a #classmethod to return the value.
Another thing, your __str__ could be made more clear using .format()

Categories