Problems with multiplying a class variable with an instance - python

I am new to pyhton and also new to working with classes. I am working on the below problem where I want to multiply the class variable (raise_amount) by the instance salary. However, when i do this, I get None as output. I would like to get the salary amount per person multiplied by 1.04. Any help will be greatly appreciated.
class Person:
raise_amount = 1.04
def __init__(self, name, street_name, house_nr, post_code, salary): #:post_code, salary):
self.name = name
self.street_name = street_name
self.house_nr = house_nr
self.post_code = post_code
self.salary = salary
def street_name_and_house_nr(self):
return '{} {}'.format(self.street_name, self.house_nr)
def apply_raise(self): # here is the code that seems to have problems
self.salary = int(Person.raise_amount * self.salary)
def street_name_and_house_nr_salary(self):
return self.name + ' ' + str(self.salary)
prs_1 = Person("Mary's", 'Broadway', 304, '2526 CG', 10)
prs_2 = Person("Jhon's", 'Longstreet', 304, '2829 AK',7)
prs_3 = Person("Larry's", 'Chinstreet', 58, '3046 JP', 8)
print(Person.apply_raise(prs_1))
print(Person.apply_raise(prs_2))
print(Person.apply_raise(prs_3))
This is the output i get when i run the code
None
None
None

apply_raise() doesn't return the new salary, it just updates the salary attribute. So you should get that separately to print it.
prs_1.apply_raise()
print(prs_1.salary)
Other notes:
Conventionally the first argument to methods is self. Don't make up your own name (what does lelf mean?).
You should call methods using instance.method(), not Class.method(instance). This ensures that the proper method will be used when the instance is in a subclass.

Related

Why is it when I call an attribute of my class, it is printing an older variable instead of the latest one?

I am working with Python class and methods at the moment, and I have the following code:
class Employee:
def __init__(self, first,last):
self.first = first
self.last = last
self.email = first + '.' + last + "#gmail.com"
def fullname(self):
return f'{self.first} + {self.last}'
emp_1 = Employee('John','Smith')
empl_1.first = 'Patrick'
print(emp_1.first)
print(emp_1.email)
print(emp_1.fullname())
And the output is:
Patrick
John.Smith#gmail.com
Patrick Smith
What I am struggling to understand is that when I print the first name by itself, and the full name of the employee, it is using the latest first name, which is defined to be 'Patrick'. However, for the email function, it is still using 'John'. Can someone kindly explain why this is the case?
You only define self.email once - when initialising the object. It will not magically update whenever you change other variables.

Python project help (classes/expected type)

I am working on a project for school, simulating a payroll program, and I am getting an error. The error I am getting is
'Expected type 'Classification', got 'Employee' instead'. The relevant code is (I put *** around the code generating the error, it is the 5th function under the Employee Class).
class Employee:
def __init__(self, emp_id, first_name, last_name, address, city, state, zipcode, clas = None):
self.emp_id = emp_id
self.first_name = first_name
self.last_name = last_name
self.address = address
self.city = city
self.state = state
self.zipcode = zipcode
self.classification = clas
def make_hourly(self, hourly_rate):
self.clas = Hourly(hourly_rate)
self.classification = self.clas
def make_salaried(self, salary):
self.clas = Salaried(salary)
self.classification = self.clas
def make_commissioned(self, salary, rate):
self.clas = Commissioned(rate, salary)
self.classification = self.clas
def issue_payment(self):
***pay = Classification.compute_pay(self)***
print('Mailing', pay, 'to', self.first_name, self.last_name, 'at', self.address, self.city, self.state, self.zipcode)
class Classification(ABC):
''' Interface for employee classifications '''
#abstractmethod
def compute_pay(self):
pass
class Hourly(Classification):
''' Manages timecard info. Computes pay '''
def __init__(self, hourly_rate):
self.hourly_rate = hourly_rate
self.timecards = [] # A list of floats representing hours worked
def compute_pay(self):
for i in list_of_timecards:
if i[0] == self.emp_id:
self.timecards.extend(i[1:])
total = list(map(float, self.timecards))
total = sum(total)
self.timecards.clear()
return total * self.hourly_rate
def add_timecard(self, hours):
self.timecards.append(hours)
class Salaried(Classification):
def __init__(self, salary):
self.salary = salary
def compute_pay(self):
return self.salary / 24
class Commissioned(Salaried):
def __init__(self, salary, commission_rate):
self.commission_rate = commission_rate
self.salary = salary
self.receipts = []
def add_receipt(self, amount):
self.receipts.append(amount)
def compute_pay(self):
for i in list_of_receipts:
if i[0] == self.emp_id:
self.receipts.extend(i[1:])
total = list(map(float, self.receipts))
total = sum(total)
self.receipts.clear()
return (self.salary / 24) + ((self.commission_rate / 100) * total)
My understanding of the problem is that I need to pass my 'employee' object to the 'compute_pay' function, which then passes it to the relevant child class (hourly etc...) to run and return the result. I have tried changing
pay = Classification.compute_pay(self)
to
pay = Classification.compute_pay(self.clas)
however that returns error 'AttributeError: 'Employee' object has no attribute 'clas'
which makes no sense. Maybe it is that I am not assigning the employees to the class correctly?
The code for that is (it pulls from a CSV file, and it is pulling the data correctly and generating the class objects, I have checked)
def load_employees():
f = open("employees.csv")
f.readline() # skip header line
for line in f:
fields = line.strip().split(',')
emp = Employee(*fields[:7])
if fields[7] == '3':
clas = Hourly(fields[10]) # Need to define Hourly
emp.classification = clas
elif fields[7] == '2':
clas = Commissioned(fields[8], fields[9])
emp.classification = clas
elif fields[7] == '1':
clas = Salaried(fields[8])
emp.classification = clas
employees.append(emp)
I will figure out your line Classification.compute_pay(self):
Classification => the class Classification
compute_pay => class
method self => this = an Employee instance
pass means do nothing and is used to avoid unneccessary code.
Every class method has self as an argument to allow refering to this instance of the class.
To pass an argument (here your employee) use a parameter. Also implementing a method of the parent class overrides this method.
Every function compute_pay should have a second argument
def compute_pay(self, employee):
# do your stuff
And then you can use this line in issue_payment
pay = self.clas.compute_pay(self)
Two issues here,
Firstly, your Employee instance has two attributes: clas and classification. However, in your constructor, only classification is set.
def __init__(...
...
self.classification = clas
But self.clas is not set to anything. That's why you are getting that error 'Employee' object has no attribute 'clas'. It is only set when one of the make_hourly, make_salaried, or make_commissioned methods are invoked. So when you load the employees CSV, instead of manually creating the instance like you are doing here
clas = Hourly(fields[10])
you should be calling the method make_hourly on your emp instance, like so
emp.make_hourly(fields[10])
It's worth noting that fields[10] is terrible naming. Instead of unpacking all the fields at once, try to unpack them during the for loop:
for a, b, c, d in csv:
...
Secondly, this line of code is wrong in multiple ways
pay = Classification.compute_pay(self)
compute_pay is not a static function or a classmethod. So it shouldn't be called on the Classification class itself, but the Classification instance. This is what you stored in your self.clas attribute. So, compute_pay should be called on self.clas:
def issue_payment(self):
pay = self.clas.compute_pay()
...
In addition to that, when you call a method of a class from inside of another method in the same class, you don't ever need to pass the self argument. It is implied. So even if compute_pay was static or a class method, which it isn't, it would be called like so,
Classification.compute_pay()
Notice there is no self inside the parentheses. Similarly, when you call another method that is not static, self is never passed as an argument:
def my_method(self):
self.another_method()

how assign list attributes to a class python 3 [closed]

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 5 years ago.
Improve this question
I need to create a class student and then assign him or her a subject (maths, science, etc.) and then the grade by subject.
Basically, I have created a class student with name, gender,etc. Then I need to add more than one subject.
But i dont understand how one student object can get more than one subject and probably a greade per subject.
class student:
def __init__(self,name,age,gender,subject):
self.name = name
self.age = age
self.gender = gender
self.subject = subject
def __str__(self):
return ('{},{},{},{}'.format(self.name,self.age,self.gender,self.subject))
new = student('Alan',17,'M','Science')
Please if someone can help me to clarify a little bit I appreciate.
thanks
From your question, I gather that you have already worked with entity relations (ERDs), which is why you are thinking in terms of associations -- which is good. I'm assuming this is homework, so I don't want to give away too much. However, the code below should get you started.
from typing import List, Dict
class CollegeClass:
def __init__(self, class_code: str, name: str):
self.class_code = class_code #type: str
self.name = name
def __str__(self):
return f"{self.class_code}, {self.name}"
def __repr__(self):
return str(self)
class Student:
def __init__(self):
self.current_classes = dict() # type: Dict[str, CollegeClass]
def enroll(self, college_class: CollegeClass):
if college_class.class_code in self.current_classes:
print("The student is already taking the class.")
return
self.current_classes[college_class.class_code] = college_class
if __name__ == '__main__':
math = CollegeClass("mth101", "Intro to Math")
english = CollegeClass("eng201", "Intro to Fiction")
eric_praline = Student()
eric_praline.enroll(math)
eric_praline.enroll(english)
for _, cls in eric_praline.current_classes.items():
print(cls)
There are many ways to accomplish this task. One solution is to not specify the subject when creating the student. Instead, you would create the student object and then add subjects to it.
For example:
student = Student(name="John Smith")
for subject_name in ("Math", "Science", "Literature"):
student.add_subject(subject_name)
That gives you a new student who has three subjects. The add_subject method might look something like this:
class Student(object):
def __init__(self, name, age, gender):
...
self.subjects = {}
...
def add_subject(self, name):
self.subjects[name] = Subject(name)
To assign grades you would do something like this, perhaps
student.add_grade("Math", "A")
student.add_grade("Science", "B")
student.add_grade("Literature", "C")
add_grade would then take the grade name, look up the subject object from self.subjects, and call a method on that subject object to add the grade.
For example:
def add_grade(self, subject_name, grade):
subject = self.subjects[subject_name]
subject.add_grade(grade)
Your class Subject could be something very simple:
class Subject(self):
def __init__(self, name):
self.name = name
self.grade = None
def add_grade(self, grade):
self.grade = grade
Note: the above assumes you want a single grade per subject. If you want multiple grades, you can change self.grade to be self.grades and have it be a list.
Class Student represents just a type of people
Object of class Student represents a particular student, e.g. John Smith
Class Subject represents something students can learn in general
Object of class Subject represents a particular class students can take, e.g. Math 2017
Grade does not belong in either of these, because it only makes sense with a combination of both. So I would suggest creating some data storage, e.g. a list of tuples to store a grade for each combination of student/subject objects you want to keep track of, e.g.
Grades = [
(john_smith, math_2017, 'A+'),
...
]
class Subject(object):
def __init__(self, name, grade=None):
self.name = name
self.grade = grade
class student:
def __init__(self,name,age,gender, subjects=[]):
self.name = name
self.age = age
self.gender = gender
self.subjects = {}
for sub in subjects:
self.subjects[sub] = Subject(sub)
# Create new student with 2 subjects (Art and Science)
new = student('Alan',17,'M', subjects=['Art', 'Science'])
# You can wrap the following processes in functions if so desired
# Add a new subject later on (Math)
new.subjects['Math'] = Subject('Math')
# Add grades
new.subjects['Art'].grade = 'C'
new.subjects['Science'].grade = 'A+'
new.subjects['Math'].grade = 'B-'
# Get a list of subjects and grades
print([(sub.name, sub.grade) for _, sub in new.subjects.items()])
>>>[('Art', 'C'), ('Science', 'A+'), ('Math', 'B-')]
But i [don't] understand how one student object can get more than one subject and probably a [grade] per subject.
Pass in a dictionary of {subject: grade} pairs.
Code
class Student:
def __init__(self, name, age, gender, subjects=None):
self.name = name
self.age = age
self.gender = gender
# Handle mutable keyword defaults
if subjects is None:
self.subjects = {}
else:
self.subjects = subjects
def __repr__(self):
return ("{0.name}, {0.age}, {0.gender}, {0.subjects}".format(self))
subjects = {"Math": "A", "Biology": "B-", "Chemistry": "A"}
s = Student("Joe", 20, "M", subjects=subjects)
s
# Joe, 20, M, {'Math': 'A', 'Chemistry': 'A', 'Biology': 'B-'}
s.subjects["Math"]
# 'A'
Assigning None to a keyword argument is a convention for avoiding a well-known gotcha when assigning mutable arguments, e.g. lists, dictionaries. The lines that handle subjects is equivalent to this one-liner:
self.subjects = {} if subjects is None else subjects
The __repr__() method was defined, which you may wish to include along with __str__().

Functions and attributes of a person via dictionaries

I'm really struggling trying to understand functions and how they can be used to create attributes or properties (in this case i'm tasked with a person)
The following is my code to declare the person in a dictionary,
def format(person):
return "Name:\t" + person['name']
def display(person):
print(format(person))
person = {'name':"Bilbo Baggins"}
I then can call the display to produce;
Name = Bilbo Baggins
I then have to add to the dictionary a property storing the weight and height (say both of which are 0 for now) of my person, which i have done by;
person['height'] = 0
person['weight'] = 0
I now need to create a function (called create_person) that has the 3 parameters (name, height and weight), and modify my earlier code to use this function and alongside printing Name: Bilbo Baggins also prints the weight(in kg) and height(in m).
The overall aim of this is to find out the BMI of a person, BMI is calculated by weight/height2. I also need to add a function that takes a single person object from the previous dictionary/function as a parameter and returns the BMI of the person. Is that possible through linking the two?
class Person:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
# This is called when you print(PERSON OBJECT)
def __repr__(self):
return self.name + " " + self.height + " " + self.weight
def BMI(self):
return (self.weight/self.height)/self.height
This allows you to create a person like so:
person_one = Person("Bilbo", 177, 72.7)
print(person_one)
bmi = person_one.BMI()

using a class instead of a list python

I have the following code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys import re
companies = {}
for line in open('/home/ibrahim/Desktop/Test.list'):
company, founding_year, number_of_employee = line.split(',')
number, name = company.split(")")
companies[name] = [name, founding_year, number_of_employee]
print "Company: %s" % company
CompanyIndex = raw_input('\n<Choose a company you want to know more about.>\n\n<Insert a companyspecific-number and press "Enter" .>\n')
if CompanyIndex in companies:
name, founding_year, number_of_employee = companies[CompanyIndex]
print 'The companys name is: ',name,'\nThe founding year is: ', founding_year,'\nThe amount of employees is: ', number_of_employee
else:
print"Your input is wrong."
This program reads some information from a text file which looks like this:
(1)Chef,1956,10
(2)Fisher,1995,20
(3)Gardener,1998,50
My aim is to get a class, where I can save the information about the company's name, the founding year, and the number of employees instead of using the dictionary which also contains a list.
I read several tutorials but I really do not know how to do that. It was really confusing what this "self" is what __init__ and __del__ does and so on. How do I go about doing this?
You can do:
class Company(object):
def __init__(self, name, founding_year, number_of_employee):
self.name = name
self.founding_year = founding_year
self.number_of_employee = number_of_employee
After that you can create a Company object by writing company = Company('Chef', 1956, 10).
Here's an example of how you could create a CompanyInfo class.
class CompanyInfo(object):
def __init__(self, name, founded_yr, empl_count):
self.name = name
self.founded_yr = founded_yr
self.empl_count = empl_count
def __str__(self):
return 'Name: {}, Founded: {}, Employee Count: {}'.format(self.name, self.founded_yr, self.empl_count)
And here's an example of how you might create it:
# ...
for line in open('/home/ibrahim/Desktop/Test.list'):
company, founding_year, number_of_employee = line.split(',')
comp_info = CompanyInfo(company, founding_year, number_of_employee)
And here's an example of how you might use it:
print "The company's info is:", str(comp_info)
class companies(object):
def __init__(self,text_name):
text_file = open(text_name,'r')
companies = {}
all_text = text_file.read()
line = all_text.split('\n') #line is a list
for element in line:
name,year,number = element.split(',')
companies[name] = [year,number]
self.companies = companies
def get_information(self,index):
print self.companies[index]
#an instance of the class defined above
my_company = companies(r'company.txt')
#call function of my_company
my_company.get_information(r'Gardener')
class Company:
def __init__(self, name, year_of_funding, num_of_employees):
'''
This is the constructor for the class. We pass the
info as arguments, and save them as class member variables
'''
self.name = name
self.year_of_funding = year_of_funding
self.num_of_employees = num_of_employees
def get_name(self):
'''
This method returns the company name
'''
return self.name
def get_year_of_funding(self):
'''
This method returns the year the company was funded
'''
return self.year_of_funding
def get_num_of_employees(self):
'''
This method returns the number of employees this company has
'''
return self.num_of_employees
Then you can create an instance of the class, and use the get methods to fetch the data:
my_company = Company('Microsoft', 1964, 30000)
print my_company.get_name() + ' was funded in ' + str(my_company.get_year_of_funding()) + ' and has ' + str(my_company.get_num_of_employees()) + ' employees'
# OUTPUT: Microsoft was funded in 1964 and has 30000 employees

Categories

Resources