Python error: object has no attribute - python

I'm new to coding -- taking a Python college course. I know this will be obvious to many of you, but I can not figure out why I continue to get this error attribute error:
prodworker = employee.ProductionWorker(shift_num, pay_rate)
AttributeError: 'Employee' object has no attribute 'ProductionWorker'
Any help is greatly appreciated :)
class Employee: #writing new class called Employee:
def __init__(self, name, number): #accepts arguments for employee name and
self.__name = name #employee number
self.__number = number
def set_name(self, name): #mutator methods to set name and number
self.__name = name
def set_number(self, number):
self.__number = number
#accessor methods returns name and number
def get_name(self):
return self.__name
def get_number(self):
return self.__number
class ProductionWorker(Employee): #write subclass
def __init__(self, shift_num, pay_rate):
Employee.__init__(self, 'ProductionWorker')
self.__shift_num = shift_num
self.__pay_rate = pay_rate
def set_shift_num(self, shift_num):
self.__shift_num = shift_num
def set_pay_rate(self, pay_rate):
self.__pay_rate = pay_rate
def get_shift_num(self):
return self.__shift_num
def get_pay_rate(self):
return self.__pay_rate
#This program creates an instance of Employee Class
#and an instance of Production Worker Class:
again = 'Y'
while again.upper() == 'Y':
print('Enter the following data for the employee: \n')
name = input('What is the employee name?: ')
number = input('What is the employee number? ')
shift_num = input('What is the employee shift number? 1 = Day, 2 = Night :')
while shift_num != '1' and shift_num != '2':
shift_num = input('Invalid entry! Enter 1 for Day shift or 2 for Night shift!')
else:
if shift_num == '1':
shift_num = 'Day'
if shift_num == '2':
shift_num = 'Night'
pay_rate = float(input('What is the employee pay rate? '))
print()
print('This is an instance of the Employee class:')
employee = Employee(name, number)
print('EMPLOYEE: \t\t'+ employee.get_name())
print('EMPLOYEE NUMBER: \t' + employee.get_number())
print()
print('This is an instance of the Production Worker class: ')
prodworker = employee.ProductionWorker(shift_num, pay_rate)
print('SHIFT: \t\t\t' + ProductionWorker.get_shift_num())
print('PAY RATE: \t\t$' + format(ProductionWorker.get_pay_rate(), ',.2f'), sep='')
print('--------------------------------------------')
again = input('Enter Y to add another: ')
if again.upper() != 'Y':
print('Program End')

The ProductionWorker class is a subclass of the Employee class, but that doesn't mean you can call it through an instance of Employee. It's still a top-level class that you should call directly. Try replacing employee.ProductionWorker(...) with just ProductionWorker(...).
You'll get past the current error, but you may have new ones. For instance, I think the current attempt to call Employee.__init__ from ProductionWorker.__init__ will fail because it doesn't pass the right number of arguments. You may also have logic issues, if you expected employee.ProductionWorker to create a ProductionWorker instance that was related in some way to the employee object.
I'd also discourage you from using __double_leading_underscore names for your attributes. That invokes Python's name mangling system, which is mostly intended to help prevent accidental reuse of the same name from different classes in a large or unpredictable inheritance hierarchy. If you just want your attributes to be "private", use a single underscore. That doesn't protect them from being accessed by outside code, but it serves as documentation that they're not part of the object's public API. One of Python's design philosophies is that it's programmers are responsible for their own behavior (often described with the phrase "We're all consenting adults"). If a programmer wants to access an object's private data they can do so (which can be very useful for debugging). But if they break stuff, they have no one to blame but themselves.

Related

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

AttributeError: "type object 'Employee' has no attribute 'Worker'"

Taking a class on Python coding and trying to use inheritance to code an answer to this problem: Write an Employee class that keeps data attributes for the following piece of information:
Employee name
Employee ID
Employee phone #
Next, write a class named ProductionWorker class should keep data attributes for the following information:
Shift number (an integer, such as 1, 2, 3)
Room (bakery, topping, Quality control)
Hourly pay rate
The workday is divided into two shifts: day and night. The shift attribute will hold an integer value representing the shift that the employee works. The day shift 1 and the night shift is shift 2. Write the appropriate accessors and mutator methods for each class.
Once you have written the classes, write a program that creates an object of the ProductionWorker class which prompts the user to enter data for each of the object's data attributes. Store the data in the object, then use the object's accessor methods to retrieve it and display it to the screen.
Why am I getting the error I described in the title?
My Code:
class Employee(object):#Creates Superclass Employee
def __init__(self,name,EmplId,EmpPhone):#Creates Employee class with several parameters
self.name = name#Initial Attribute for Employee Name
self.EmplId = EmplId#Initial Attribute for Employee ID #
self.EmpPhone = EmpPhone#Initial attribute for Employee Phone #
class Worker(Employee):#Creates Subclass of Employee called Worker
def __init__(self,name,EmplId,ShiftNum,EmpPhone,PayRate):#Set initial state of Worker Subclass
Employee.__init__(self,name,EmplId,EmpPhone)
self.ShiftNum = ShiftNum#Initial Shift number value for class Worker
self.PayRate = PayRate#Initial Payrate for class Worker
def main():#Creates Main method
WorkerName = " "
WorkerIDNum = " "
WorkerShiftNum = 0
WorkerPayRate = 0.0
WorkerPhoneNum = " "
#Getting data attributes to passed into Employee and Worker classes
WorkerName = input("Enter the Workers name: ")
WorkerIDNum = ("Enter the Workers Id Number: ")
WorkerShiftNum = input ("Enter the Workers shift number (1,2,or 3): ")
WorkerPayRate = input ("Enter the works payrate in dollars an cents: ")
WorkerPhoneNum = input ("Enter the employees 9 Digit phone number:")
worker = Employee.Worker(WorkerName,WorkerIDNum,WorkerShiftNum,WorkerPhoneNum,WorkerPayRate)
#Above line creates an Instance of the Employee superclass and Worker subclass called "worker"
#Values the user entered are pass in as attributes to the object.
#Printing User entered information
print("Worker information entered: ")
print("Name: ", worker.name)
print("EMployee ID Number: ", worker.EmplId)
print("Employee Shift Number: ", worker.ShiftNum)
print("Worker Hourly Payrate: $", worker.PayRate)
main()```
The solution to your problem was provided in the comments... you must instantiate only the subclass (ie. Worker, not Employee.Worker), but I see more problems. My example below illustrates one way to fix them. You are creating a lot of arbitrary values, and not performing any checks or limits on them. Everything comes from outside of your class and needs to be clumsily injected into the __init__ arguments. Then to print the Worker you gather all of the data externally and format it into print statements. Why not make your classes smart enough to handle all of this internally?
To put this another way. You are basically just grabbing a bunch of junk, throwing it in a class constructor and calling it a Worker. You should be able to just call Worker and it handles getting, formatting and limiting everything that it expects.
Below we store all the final values in private variables. We tie all assignments to "setters" and trigger those "setters" in __init__. This allows us to force variables to satisfy certain conditions before we accept them. It also allows us to change properties of the Worker (after instantiation) while following the exact same system.
#Creates Superclass Employee
class Employee(object):
#property
def name(self) -> str:
return self.__name
#name.setter
def name(self, name:str) -> None:
while not name:
name = input("Enter The Worker's Name: ")
self.__name = name
#property
def phone(self) -> str:
return self.__phone
#phone.setter
def phone(self, phone) -> None:
phone = f'{phone}'
#get and check phone
while not phone.isdigit() or len(phone) != 10:
phone = input("Enter The Worker's 10 digit Phone Number: ")
#store phone
self.__phone = phone
#property
def eid(self) -> int:
return self.__eid
#eid.setter
def eid(self, eid) -> None:
if not isinstance(eid, int):
eid = f'{eid}'
#get and check employee id
while not eid.isdigit():
eid = input("Enter The Worker's ID Number: ")
eid = int(eid)
#store id
self.__eid = eid
def __init__(self):
self.name, self.phone, self.eid = '', '', ''
#Creates Subclass of Employee called Worker
class Worker(Employee):
#property
def shift(self) -> int:
return self.__shift
#shift.setter
def shift(self, shift) -> None:
if not isinstance(shift, int) or (isinstance(shift, int) and shift not in (1, 2, 3)):
shift = f'{shift}'
#get and check shift number
while not shift.isdigit() or not shift in ('1', '2', '3'):
shift = input("Enter The Worker's Shift Number (1, 2, 3): ")
shift = int(shift)
#store shift
self.__shift = shift
#property
def rate(self) -> float:
return self.__rate
#rate.setter
def rate(self, rate) -> None:
if not isinstance(rate, (float, int)):
rate = f'{rate}'
#get and check pay rate
while True:
try:
float(rate)
break
except ValueError:
pass
rate = input("Enter The Worker's Pay Rate in Dollars and Cents: ")
rate = float(rate)
#store rate
self.__rate = rate
def __init__(self):
Employee.__init__(self)
self.shift, self.rate = '', ''
#for printing the worker props
def __str__(self):
return f'Worker Information:\n\tname: {self.name}\n\tid: {self.eid}\n\tphone: {self.phone}\n\tshift: {self.shift}\n\trate: {self.rate}'
#this is so much cleaner. Make a Worker and print the instance.
if __name__ == "__main__":
worker = Worker()
print(worker)

Python Class and encapsulation methods

I'm new to OOP and this is my first shot at creating a Python class. I am trying to make my 3 variables private and so that only the methods update the info (enforce encapsulation). It seems that if I remove the setters and getters methods from my class, it has no impact on my code (must be the initializer method doing the work?). What can I do to improve this? Thanks.
Edit- i've updated my code and removed the init. My getters are not working now.
#Instantiate a new Pet Instance.
myPet = Pet()
#Get input from user.
myPet.setName = input("Enter the pet's name: ")
myPet.setTypes = input("Enter the pet's type (Dog, Cat, Bird, etc.): ")
myPet.setAge = input("Enter the pet's age (in years): ")
while myPet.setAge.isalpha():
print()
print("Age cannot contain numbers. Try again.")
myPet.setAge = input("Enter the pet's age (in years): ")
#Call the showPetInfo module using new instanced object.
myPet.showPetInfo()
class Pet:
#Fields of the Pet Class.
__PetName = ""
__PetType = ""
__PetAge = ""
#Setter methods.
def setName(self,name):
self.__PetName = name
def setTypes(self,types):
self.__PetType = types
def setAge(self,age):
self.__PetAge = age
#Getter methods.
#property
def getName(self):
return self.__PetName
#property
def getType(self):
return self.__PetType
#property
def getAge(self):
return self.__PetAge
def showPetInfo(self):
print("\n \n \n \n")
print("Here is your pet's information. Your pet's name is {}, it is a {} and it is {} years old.".format(self.getName,self.getType,self.getAge))
main()
you are unfortunately right, they use to say setters/getters are contracts doing restriction for adults... (if I tell you "dont touch it" then you shoulntd touch it) but there is nothing restricting you and you can modify them!
same "feature" can be observed with "constants"... do in the jupyther or the terminal this
import math
math.pi = 1
a = math.pi
a
math.pi
and you will see that you now modified the constant pi value to 1
many sugest to usse properties but that is not a capsulation at all, that is just sugar syntax for the same "adults contract" IMHO :)
so to your question
What can I do to improve this?
document the code you are writing so the other part using it is aware about how the code, instances states in objects must be handled

How to use functions inside #classmethod decorator

When using #classmethod this is passed first instead of self. Now inside the method with this decorator i need to call functions that are not defined inside this decorator but are defined in the class. How can i call the two functions get_int_input and get_non_int_input so that i can pass them to the return cls(name,pay_rate,hours) statement?
class Employee(object):
def __init__(self,name,pay_rate,hours):
self.name = name
self.pay_rate = pay_rate
self.hours = ("mon","tues","wed","thursday","friday","saturday","sunday")
def get_int_input(prompt):
while True:
pay_grade = raw_input(prompt)
try:
i = int(pay_grade)
except ValueError:
print "Int Only"
else:
return i
def get_non_int_input(prompt):
while True:
a_name = raw_input(prompt)
try:
i = int(a_name)
except ValueError:
return a_name
else:
print " Strings Only"
#classmethod
def from_input(cls):
day_count = 1
hours = ("m","tue","w","thur","f","s","sun")
while day_count <= 7:
for day in hours:
day = input(" Enter hours for day " + str(day_count) + "--- ")
day_count += 1
return cls(name,pay_rate,hours)
name = get_non_int_input("\n Enter new employee name\n")
pay_rate = get_int_input("Enter pay rate ")
employee = Employee.from_input()
print str(employee)
You would add the #staticmethod decorator before the other two classes. Since they don't take either the Employee class or one of its instances as their first argument, they operate independently of a particular class or instance, and in this sense are "static".
A method decorated in this manner is an attribute of its containing class, and is called as a class attribute, for example:
>>> class Foo(object):
... #staticmethod
... def bar():
... print 'called the static method'
...
>>> Foo.bar()
called the static method
This works the same way if you're calling Foo.bar() from inside one of Foo's class methods.
There are some other problems here, though - I would advise you to seek more comprehensive review and advice.
You defined get_int_input and get_non_int_input inside the Employee class, which means that (by default) they should take an instance of Employee as the first argument. Your code is breaking that rule, which is probably the cause of problems.
Use #staticmethod decorator to indicate that get_int_input and get_non_int_input should not take an instance of Employee as the first argument.
you seem to be missing some core concept of programming
you should probably look up namespaces and scope in google.
you should probably not talk down to john.r.sharp as he is very helpful and I would hazard a guess that if you continue programming you will have many many more problems that you come to SO for help with
all that said here is your fixed code
#first pull these two functions out of your class they have nothing to do with employee
#they should just be normal functions #
#... if you wanted to make them part of a class make an input class and add them as static methods to that
def get_int_input(prompt):
while True:
pay_grade = raw_input(prompt)
try:
i = int(pay_grade)
except ValueError:
print "Int Only"
else:
return i
def get_non_int_input(prompt):
while True:
a_name = raw_input(prompt)
try:
i = int(a_name)
except ValueError:
return a_name
else:
print " Strings Only"
class Employee(object):
def __init__(self,name,pay_rate,hours):
self.name = name
self.pay_rate = pay_rate
self.hours = ("mon","tues","wed","thursday","friday","saturday","sunday")
#classmethod
def from_input(cls):
day_count = 1
hours = ("m","tue","w","thur","f","s","sun")
while day_count <= 7:
for day in hours:
day = input(" Enter hours for day " + str(day_count) + "--- ")
day_count += 1
#name and pay_rate must be defined prior to using them in your return function ...
name = get_non_int_input("\n Enter new employee name\n")
pay_rate = get_int_input("Enter pay rate ")
#now that you have all the info just return it
return cls(name,pay_rate,hours)
employee = Employee.from_input()
print str(employee)

Python: Class and SubClass - Why won't in recognize the subclass

I am trying to create a class that contains the salary and bonus attributes and another that contains the name and idnum attributes. With a small program that asks if the shift has met goal for the year and then figures the total income for the shift supervisor for the year. Every time I try I get:
File "C:\Python33\12-2.py", line 53, in main
shift1 = Shiftsupervisor.Employee('28000.0','2240.0','Ian McGregor', 'S10001' )
AttributeError: type object 'Shiftsupervisor' has no attribute 'Employee'
What have I done wrong??
# This creates two classes - ShiftSupervisor & Employee
# The program then tells us what the annual income is
# This creates a class of Super Class Shiftsupervisor which contains salary, & bonus \
figures
class Shiftsupervisor:
#Initialize the Shiftsupervisor attributes
def __init__(self, salary, bonus):
self.__salary = salary
self.__bonus = bonus
# creates the mutator for the attributes
def set_salary(self, salary):
self.__salary = salary
def set_bonus(self, bonus):
self.__bonus = bonus
# returns the attributes
def get_salary(self):
return self.__salary
def get_bonus(self):
return self.__bonus
#Create the subclass of employee which holds the name & idnum
#Initialize the employee attributes
class Employee(Shiftsupervisor):
def __init__(self, salary, bonus, name, idnum):
Shiftsupervisor.__init__(self, salary, bonus)
#Initialize the employee new attributes
self.__name = name
self.__idnum = idnum
#creates the new mutator for name & id
def set_name(self, name):
self.__name = name
def set_idnum(self, idnum):
self.__idnum = idnum
# new method returns the name & id
def get_name(self):
return self.__name
def get_idnum(self):
return self.__idnum
#This program take info from the two classes and gives
# the total income for the Shift Supervisor
#Creates the shift supervisor objects
def main():
shift1 = Shiftsupervisor.Employee('28000.0','2240.0','Ian McGregor', 'S10001' )
shift2 = Shiftsupervisor.Employee('29500','2360.0','Brian Bory', 'S20202' )
shift3 = Shiftsupervisor.Employee('28750.0','2300.0''Finn McCool', 'S30045' )
def total_income():
if production == 'y' or 'Y':
return __salary + __bonus
else:
return __salary
#Ask the Question - Did they make production quota
production = input('Did Shift 1 make quota this year? Type Y for yes ' )
#Print the income
print(shift1.get_name(),'s Total income is: $', format(total_income, \
',.2f'), sep='')
#Ask the Question - Did they make production quota
production = input('Did Shift 2 make quota this year? Type Y for yes ' )
#Print the income
print(shift2.get_name(),'s Total income is: $', format(total_income, \
',.2f'), sep='')
#Ask the Question - Did they make production quota
production = input('Did Shift 3 make quota this year? Type Y for yes ' )
#Print the income
print(super3.get_name(),'s Total income is: $', format(total_income, \
',.2f'), sep='')
#call the main function
main()
Your code has the following problems:
I think it'd be better have ShiftSupervisor be a subclass of Employee. Unless I'm misunderstanding, a shift supervisor is a kind of employee, so employee is the base class. A shift supervisor might have additional attributes that specialize the Employee class. I've added the shift_number attribute to demonstrate this.
Your main method only creates the employees, but doesn't ever do anything with them.
Your total_income method is a bit confused. Remember, __salary and __bonus are attributes of an object. You have do always use the form instance.attribute in order to get access to those.
You don't need getters and setters in Python. The convention is to keep them normal fields that are meant to be publicly accessible, and use properties if it turns out you do need more complex accessing logic.
The salary and bonus shouldn't be a string -- they're numeric values.
Taken together, your new code might look something like this:
class Employee:
def __init__(self, salary, bonus, name, idnum):
self.salary = salary
self.bonus = bonus
self.name = name
self.idnum = idnum
class ShiftSupervisor(Employee):
def __init__(self, salary, bonus, name, idnum, shift_number):
super().__init__(salary, bonus, name, idnum)
self.shift_number = shift_number
def main():
shift1 = ShiftSupervisor(28000.0, 2240.0, 'Ian McGregor', 'S10001', 1)
shift2 = ShiftSupervisor(29500, 2360.0, 'Brian Bory', 'S20202', 2)
shift3 = ShiftSupervisor(28750.0, 2300.0, 'Finn McCool', 'S30045', 3)
find_income(shift1)
find_income(shift2)
find_income(shift3)
def find_income(employee):
production = input('Did shift {0} make quota this year? Type Y for yes '.format(employee.shift_number))
if production.lower() == 'y':
total_income = employee.salary + employee.bonus
else:
total_income = employee.salary
print("{0}'s Total income is: ${1}".format(employee.name, total_income))
main()
I'm also getting the feeling that you're entangling a shift and an employee in some way that you shouldn't be, though I'm quite able to put my finger on it. A shift might have more than one employee, and an employee could work multiple shifts, though this'll definitely depend based on what problem you're trying to solve.

Categories