How to use functions inside #classmethod decorator - python

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)

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 error: object has no attribute

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.

If = 1 then answer is day shift else answer is night shift

with this program the outcome should display employee name, number , shift (day or night based on the number imputed) and hourly pay rate.
I've tried a few different ways and can "almost" get the desired results. Any assistance would be appreciated.
# This Employee class holds general data about employess and will
# end up as the superclass for this example.
class Employee:
#__init__ method initialzes the attributes.
def __init__(self, emp_name, emp_number):
self.__emp_name = emp_name
self.__emp_number = emp_number
# The set_emp_name method gets the employee name.
def set_emp_name(self, emp_name):
self.__emp_name = emp_name
# The set_emp_name method gets the employee number.
def set_emp_number(self, emp_number):
self.__emp_number = emp_number
# The get_emp_name method returns the employee name.
def get_emp_name(self):
return self.__emp_name
# The get_emp_number method returns the employee number.
def get_emp_number(self):
return self.__emp_number
# The ProductionWorker class holds the general data from superclass Employee
# as well as Employee shift time and pay rate making it a subclass
# of Employee.
class ProductionWorker(Employee):
# __init__ method initializes the attributes.
def __init__(self, emp_name, emp_number, shift, payrate):
# Call the superclass
Employee.__init__(self, emp_name, emp_number)
self.__shift = shift
self.__payrate = payrate
# The set_shift method get employee shift.
def set_shift(self, shift):
self.__shift = shift
# The set_payrate method gets employee hourly pay rate.
def set_payrate(self, payrate):
self.__payrate = payrate
# The get_shift method returns the employee shift.
def get_shift(self):
if self.shift == 1:
self.shift = 'Day shift'
elif self.shift == 2:
self.shift = 'Night shift'
return self.__shift
# The get_payrate method returns the employee hourly pay rate.
def get_payrate(self):
return self.__payrate
# This program will test the Employee superclass and ProductionWorker subclass
# by returning and displaying the gathered information.
import sys
# Get the Employee info.
emp_name = input('Employee Name: ')
emp_number = input('Employee Number: ')
shift = float(input ('Shift Number 1 or 2: '))
payrate = input('Hourly Pay Rate: $')
# Determine True or False for mailing list.
#if shift == 1:
#print('Day')
#else:
#print ('Night')
# Create an instance of the ProductionWorker class.
my_productionworker = ProductionWorker(emp_name, emp_number, shift, payrate)
# Display the object's data.
print('Employee Information')
print('---------------------')
print('Employee Name:', my_productionworker.get_emp_name())
print('Employee Number:', my_productionworker.get_emp_number())
print('Shift:', my_productionworker.get_shift())
print('Hourly Pay Rate:$', my_productionworker.get_payrate())
In your method
def get_shift(self):
if self.shift == 1:
self.shift = 'Day shift'
elif self.shift == 2:
self.shift = 'Night shift'
return self.__shift
you're mixing up .shift and .__shift In the if and elif, it should be .__shift and in the assignments it should be just shift (a local variable, not a member variable) and then you should return that local variable (or maybe just return directly from inside the if and elif, depending on how you feel about multiple exit points).
Also, it's a good practice to include a final else in your if / elif, possibly something like this:
else:
shift = 'Cannot convert {} to a valid shift.'.format(self.__shift)
or
else:
raise Exception('Invalid shift value {}.'.format(self.__shift)
which will alert you to the fact that you fell through all the valid options, and give you a hint as to what value is causing the problem.
BTW, you should not be using double underscore variables in this way and, in general, should not try to write Java code in Python. I'd get rid of the getters and setters and just read and write the member values directly.

How do I catch NameError in Python?

I've been trying to write a simple program in python to use classes and test attributes. It asks the user to input one of the names, and uses that input to display 2 attributes of the name. I've tried to include a try...except block to catch the NameError that occurs when typing something that hasn't been defined as the name of an object, but I still get this traceback:
Traceback (most recent call last):
File "C:/Users/Bede/Documents/Technology/Programming/Python/276/testcode", line 18, in <module>
animalName = input(">")
File "<string>", line 1, in <module>
NameError: name 'Marmadukke' is not defined
I'm aware this probably isn't the best way to do things, so I'm open to all suggestions.
My full code is here:
class Dog(object):
def __init__(self,name,chasesCats):
self.name = name
self.chasesCats = chasesCats
class Cat(object):
def __init__(self,name,chasesMice):
self.name = name
self.chasesMice = chasesMice
Marmaduke = Cat("Marmaduke",True)
Timmy = Cat("Timmy",False)
Cerberus = Dog("Cerberus",True)
Max = Dog("Max",False)
print("Enter Marmaduke, Timmy, Max or Cerberus.")
animalName = input(">")
while 1:
try:
if isinstance(animalName,Cat):
print("Cat")
if animalName.chasesMice:
print("Chases mice")
else: print("Doesn't chase mice")
if isinstance(animalName,Dog):
print("Dog")
if animalName.chasesCats:
print("Chases cats")
else: print("Doesn't chase cats")
break
except NameError:
print("Try again!")
I'm guessing you're using python2.x. In that case, you should use raw_input instead of input. The problem is that on python2.x, input calls eval on the data you put in. I suppose, this means that you could put in the data as "Marmaduke" (note the quotes). But having the program behave differently depending on whether you're using python2.x or 3.x seems undesirable.
An easy way to make the code work for both, python2.x and python3.x:
try:
raw_input
except NameError:
raw_input = input
animalName = input(">") is outside of the try block. So the Error won't be caught.
Probably you want that inside the try block in the loop:
while 1:
try:
animalName = input(">")
if isinstance(animalName,Cat):
This line is the culprit:
animalName = input(">")
When you enter Marmadukke, which isn't defined yet, you get the name error, since you're trying to do:
animalName = Marmadukke #Not defined.
Wrap it in a try/except block:
try:
animalName = input(">")
except:
print("Invalid input!")
But to achieve this, it would be much better to store your animals to a dictionary, and retrieve only the name:
animals = {}
animals['Marmaduke'] = Cat("Marmaduke",True)
animals['Timmy'] = Cat("Timmy",False)
animals['Cerberus'] = Dog("Cerberus",True)
animals['Max'] = Dog("Max",False)
And to retrieve:
animalName = animals[raw_input(">")]
You can then put it inside your while function, and catch KeyError instead of NameError.
Hope this helps!
For the fun and interest, I have extended your code; try tracing through it, you should learn lots ;-)
class Mammal(object):
index = {}
def __init__(self, name, chases_what=type(None)):
Mammal.index[name] = self
self.name = name
self.chases_what = chases_what
def speak(self):
pass
def chase(self, who):
if isinstance(who, self.chases_what):
self.speak()
print('{} chases {} the {}'.format(self.name, who.name, who.__class__.__name__))
who.speak()
else:
print("{} won't chase a {}".format(self.name, who.__class__.__name__))
class Mouse(Mammal):
def speak(self):
print('Squeak! Squeak!')
class Cat(Mammal):
def __init__(self, name, chases=True):
super(Cat, self).__init__(name, Mouse)
self.chases = chases
def chase(self, who):
if self.chases:
super(Cat, self).chase(who)
else:
print("{} won't chase anything".format(self.name))
class Dog(Mammal):
def __init__(self, name, chases_what=Cat):
super(Dog, self).__init__(name, chases_what)
def speak(self):
print('Bark! Bark!')
def chase(self, who):
if self is who:
print("{} chases his own tail".format(self.name))
else:
super(Dog, self).chase(who)
# create animal instances
Mouse('Jerry')
Mouse('Speedy Gonzalez')
Cat('Garfield', chases=False)
Cat('Tom')
Dog('Max')
Dog('Marmaduke', (Cat, Mouse))
def main():
while True:
name = raw_input('Enter an animal name (or Enter to quit): ').strip()
if not name:
break
me = Mammal.index.get(name, None)
if me is None:
print("I don't know {}; try again!".format(name))
continue
chase = raw_input('Enter who they should chase: ').strip()
target = Mammal.index.get(chase, None)
if target is None:
print("I don't know {}".format(name))
else:
me.chase(target)
if __name__=="__main__":
main()

Categories