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()
Related
I have been using this basic code for a simple inventory system. I need to expand this to keep track of another list of parts that are leaving the inventory. I thought I might be able to do this by creating another namedtuple for the data structure . I have some problems because the two namedtuples would need to exist and be accessed at the same time. How can I do this in python?
import sys
from collections import namedtuple
class Part(namedtuple("Part", "name part_number quantity")):
def __str__(self):
return ", ".join(self)
class Parts(dict):
def display (self):
if not self:
print('No Parts Found in List')
return
print()
print('Name, Part Number, Quantity')
for part in self.values():
print(part)
print()
def add(self, *args):
try:
name, part_number, quantity = args
except ValueError:
name = input("Enter Name of Part:\n ")
part_number = input("Enter Part Number:\n ")
quantity = input("Enter Quantity:\n ")
self[name] = Part(name, part_number, quantity)
def remove(self, part=""):
if not part:
part = input("Enter Part Name to Remove\n")
try:
del self[part]
except Keyerror:
print("Part {} not found.".format(part))
def edit(self, part=""):
if not part:
part = input("Enter Part Name to Edit\n")
try:
new_name = input("Enter new part name\n")
number = input("Enter new part number\n ")
quantity = input("Enter new quantity\n ")
self[part] = Part(new_name, number, quantity)
except KeyError:
print("No such Part exists: {}".format(part))
def save(self, filename=""):
if not filename:
filename = input("Filename to save: ")
with open(filename, "wt") as out_file:
for part in self.values():
out_file.write("{}\n".format(part))
print("File saved")
def load(self, filename=""):
if not filename:
filename = input("Filename to load: ")
try:
with open(filename, "rt") as in_file:
for line in in_file:
if not line:
break
part, part_number, quantity = line.strip().split(",")
self.add(part, part_number, quantity)
except FileNotFoundError:
print("File Not Found.")
def menu(inventory):
menu_list = [("Parts", inventory.display),
("Add Part", inventory.add),
("Remove Part", inventory.remove),
("Edit Part", inventory.edit),
("Save Part List", inventory.save),
("Load Part List", inventory.load),
("Exit", sys.exit)]
while True:
for i, (name, _) in enumerate(menu_list, 1):
print("{}. {}".format(i, name))
try:
user = int(input("Selection> "))
menu_list[user-1][1]()
except (ValueError, IndexError):
print("Selection Not Valid.")
def main():
print("Welcome to Sticks&Stones Inventory System")
inventory = Parts()
while True:
menu(inventory)
if __name__ == '__main__':
try:
main()
except (KeyboardInterrupt, SystemExit):
print("Exiting Program...")`enter code here
`
Your two tuples (or more) can exist and be accessed at the same time, with no problem!
class Parts(namedtuple("Parts", "name part_number quantity")):
def __str__(self):
return ", ".join(self)
class RemovedParts(namedtuple("RemovedParts", "name quantity")):
pass
# etc.
With that said, let me make some suggestions:
As #juanpa.arrivillaga has already suggested, your current Parts class should not extend dict. Ask yourself, "does my system have a dictionary because it's convenient to the implementation, or is my system a dictionary because of some fundamental property?"
I think you'll see that the has-a/is-a question in this case is a pretty good way to see that you should use composition (has-a) rather than inheritance (is-a) in your design.
Consider renaming your Parts class to something different. What you're modeling is really a thing that contains information about the parts, and how many you have on hand. Perhaps PartsInfo or even Inventory would be a better class name.
Consider separating the actual management object from the user interface. Perhaps you have an Inventory object and an InventoryUI object? Move pretty much all of the functions that interact with the user into the UI class.
Write some helper functions (methods) to do things like read in part numbers or part names and confirm that they are valid. Maybe you need a pair of dictionaries, one for part-number -> part-info and the other for part-name -> part-info?
Consider using the json library to serialize your data for load/save operations.
class Main():
def __init__(self):
def placeName(self):
place_name = raw_input("\n=> Enter a place name: ")
placename_data = place_name.strip()
if re.match("^[a-zA-Z]*$", placename_data):
return placename_data
else:
print("Error! Only Alphabets from are allowed as input!")
a = Main()
new = a.placeName()
Above code for placeName() method runs correctly without using class but when I try to add it in a class, code gives an attribute error . Can't understand what is wrong here.
You don't need to define __init__ inside the Main class.
class Main():
def placeName(self):
place_name = raw_input("\n=> Enter a place name: ")
placename_data = place_name.strip()
if re.match("^[a-zA-Z]*$", placename_data):
return placename_data
else:
print("Error! Only Alphabets from are allowed as input!")
a = Main()
new = a.placeName()
Please remove __init__ method and try.
I am new to Python, am just learning Classes, and am trying to write a "personal info" program:
This is my code:
class PersonalInfo():
def names(self, name):
name = raw_input("What is your name?")
self.names = name
def addresses(self, add):
add = raw_input("What is your adress?")
self.addresses = add
def ages(self, age):
age = raw_input("What is your age?")
self.ages = age
def numbers(self, number):
number = raw_input("What is your phone number?")
self.numbers = number
PersonalInfo()
def print_names():
info = PersonalInfo()
print "Name:", info.names(name)
print "Address:", info.addresses(add)
print "Age:", info.info.ages(age)
print "Phone number:", info.numbers(number)
print_names()
But when I run it it says this:
NameError: global name 'add' is not defined
Can someone please help me?
There are several issues with your code other than the NameError and I strongly suggest you read more on python classes:
https://docs.python.org/2/tutorial/classes.html
https://www.tutorialspoint.com/python/python_classes_objects.htm
https://en.wikibooks.org/wiki/A_Beginner's_Python_Tutorial/Classes
I'll run you through those issues.
First, the NameError occurs because the add variable was not defined. The same applies to all other arguments you provided in your print statements.
Second, there are issues with the way you define the class methods:
class PersonalInfo():
def names(self, name):
name = raw_input("What is your name?")
self.names = name
Here, you are re-assigning the name variable to the return value of raw_input so there's no sense in setting it as an argument in the first place. Also, by stating self.names = name you are re-assigning the class method to the string that is returned by raw_input!
Third, you have to decide whether you want to provide the information when calling the methods, or using raw_input. Here's a working example of your code, assuming you want to use raw_input
class PersonalInfo():
def names(self):
name = raw_input("What is your name?")
self.name = name
def addresses(self):
add = raw_input("What is your adress?")
self.address = add
def ages(self):
age = raw_input("What is your age?")
self.age = age
def numbers(self):
number = raw_input("What is your phone number?")
self.number = number
def print_names():
info = PersonalInfo()
# Get information
info.names()
info.addresses()
info.ages()
info.numbers()
# After getting the info, print it
print "Name:", info.name
print "Address:", info.address
print "Age:", info.age
print "Phone number:", info.number
print_names()
I am just learning classes in Python and for the past day I am stuck with the below.
I am trying to use a user input (from the main() function) to change the value of an attribute in the class.
I have been throught the #property and #name.setter methods that allow you to change the value of a private attribute.
However I am trying to find out how you can use user input to change the value of an attribute that is not private.
I came up with the below but it does not seem to work. The value of the attribute remains the same after I run the program. Would you have any ideas why?
class Person(object):
def __init__(self, loud, choice = ""):
self.loud = loud
self.choice = choice
def userinput(self):
self.choice = input("Choose what you want: ")
return self.choice
def choiceimpl(self):
self.loud == self.choice
def main():
john = Person(loud = 100)
while True:
john.userinput()
john.choiceimpl()
print(john.choice)
print(john.loud)
main()
In choiceimpl you are using == where you should use =.
Like stated before, you are using a comparison with == instead of the =.
Also you are returning self.choice in userinput as a return value, but never use it, because you set self.choice equal to input.
Shorter example:
class Person:
def __init__(self, loud):
self.loud = loud
def set_loud(self):
self.loud = input("Choose what you want: ")
def main():
john = Person(100)
while True:
john.set_loud()
print(john.loud)
main()
1) Change: '=='(comparison operator) to '='(to assign)
2) Inside class:
def choiceimpl(self,userInp):
self.loud = self.userInp
3) Outside class
personA = Person(loud) # Create object
userInp = raw_input("Choose what you want: ") # Get user input
personA.choiceimpl(userInp) # Call object method
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)