Search code examples
pythonironpythoninstances

Iron Python get attributes of class instance, based on string input


This is my code, I'm new to python and can't understand why this wont work, I want to be able to print the class instances attributes after that particular instance has been selected by the user. I'm not sure if this is even possible but if it is some help would be greatly appreciated.

class Animal(object):
    def __init__(self, name, age, happiness, hunger):
        self.name = name
        self.age = age
        self.happiness = happiness
        self.hunger = hunger


def animal_print(animal):
    if animal.lower() in animals:
        print "%s, the %s, is %s years old. % (animal.name, animal, animal.age)


pig = Animal("Joe", 12, 7, 6)
fox = Animal("Fred", 4, 4, 6),
cow = Animal("Bessy", 9, 6, 3),
horse = Animal("Sally", 7, 8, 8),

animals = ["pig", "fox", "cow", "horse"]


animal_print(raw_input("Which animal would you like to see: "))

The basics of this code are that the user will input an animal from the animals list and then I'd like it to return the member attributes. If I change my code to the below it works but ideally I'd like just one print statement for all the class instances whereas the below would require an individual print statement for each instance:

def animal_print(animal):
    if animal.lower() in animals:
        print "%s, the %s, is %s years old % (pig.name, animal, pig.age)

Solution

  • The str 'pig' is not the same as the instance of Animal, stored in the variable pig.

    raw_input returns a str. So in the animal_print function, animal is a str. The str has no name attribute, so animal.name will raise an AttributeError.

    There are at least three ways to fix the code: Use a "whitelist" dict, lookup the value in the globals() dict, or use eval. Of these three, using a whitelist is the safest, since global lookups and eval should not be allowed on arbitrary user input. One can leak private information, and the other could allow a malicious user to run arbitrary code.

    So use a whitelist:

    animap = {'pig': pig,
              'fox': fox}
    anistr = raw_input(...)   # str
    animal = animap[anistr]   # Animal instance
    

    class Animal(object):
        def __init__(self, name, age, happiness, hunger):
            self.name = name
            self.age = age
            self.happiness = happiness
            self.hunger = hunger
    
    
    def animal_print(anistr):
        animal = animap.get(anistr.lower())
        if animal is not None:
            print "%s, the %s, is %s years old." % (animal.name, anistr, animal.age)
    
    
    pig = Animal("Joe", 12, 7, 6)
    fox = Animal("Fred", 4, 4, 6)
    cow = Animal("Bessy", 9, 6, 3)
    horse = Animal("Sally", 7, 8, 8)
    
    animap = {'pig': pig,
              'fox': fox,
              'cow': cow,
              'horse': horse}
    
    anistr = raw_input("Which animal would you like to see: ")
    
    animal_print(anistr)