0

I've been struggling for a couple of days now with the following...

I'm trying to find a way to instantiate a number of objects which I can name via a raw_input call, and then, when I need to, look at its attributes via the 'print VARIABLE NAME' command in conjunction with the str() method.

So, to give an example. Let's say I want to create a zoo of 10 animals...

    class Zoo(object): 
        def __init__(self, species, legs, stomachs):
            self.species = species
            self.legs = legs
            self.stomachs = stomachs


for i in range(9): 
    species = raw_input("Enter species name: ")
    legs = input("How many legs does this species have? ")
    stomachs = input("...and how many stomachs? ")
    species = Zoo(species, legs, stomachs)

The idea is that the 'species' variable (first line of the for loop) e.g species = Bear becomes the object 'Bear' (last line of loop), which in conjunction with a str() method and the 'print Bear' command would give me the bears attributes.

Like I say, I've struggled for a while with this but despite looking at other posts on similar themes still can't figure out a way. Some say use dictionaries, others say use setattr() but I can't see how this would work in my example.

4
  • 3
    Might help if you told us what language this is... Commented Sep 25, 2009 at 20:47
  • That language are you using? In PHP you can use $$variable_that_contains_object/var_name Commented Sep 25, 2009 at 20:48
  • 3
    this looks clearly like python Commented Sep 25, 2009 at 20:49
  • 1
    And I thought Python had become mainstream =/ Also, the poster has tagged it. Commented Sep 25, 2009 at 21:05

4 Answers 4

6

If you just want to introduce new named variables in a module namespace, then setattr may well be the easiest way to go:

import sys

class Species:
    def __init__(self, name, legs, stomachs):
        self.name = name
        self.legs = legs
        self.stomachs = stomachs

def create_species():
    name = raw_input('Enter species name: ')
    legs = input('How many legs? ')
    stomachs = input('How many stomachs? ')
    species = Species(name, legs, stomachs)
    setattr(sys.modules[Species.__module__], name, species)

if __name__ == '__main__':
    for i in range(5):
        create_species()

If you save this code to a file named zoo.py, and then import it from another module, you could use it as follows:

import zoo
zoo.create_species() # => enter "Bear" as species name when prompted
animal = zoo.Bear # <= this object will be an instance of the Species class

Generally, though, using a dictionary is a more "Pythonic" way to maintain a collection of named values. Dynamically binding new variables has a number of issues, including the fact that most people will expect module variables to remain fairly steady between runs of a program. Also, the rules for naming of Python variables are much stricter than the possible set of animal names -- you can't include spaces in a variable name, for example, so while setattr will happily store the value, you'd have to use getattr to retrieve it.

Sign up to request clarification or add additional context in comments.

1 Comment

+1 for the last paragraph. A dictionary is the right way to go.
1

It's really, truly, SERIOUSLY a bad idea to create barenamed variables on the fly -- I earnestly implore you to give up the requirement to be able to just print FOOBAR for a FOOBAR barename that never existed in the code, much as I'd implore a fellow human being who's keen to commit suicide to give up their crazy desires and give life a chance. Use dictionaries, use a function that takes 'FOOBAR' as the argument and looks it up, etc.

But if my fellow human being is adamant about wanting to put an end to their days, I might switch to suggestions about how to do that with the least collateral damage to themselves and others. The equivalent here would be...:

class Zoo(object): 
    def __init__(self, species, legs, stomachs):
        self.species = species
        self.legs = legs
        self.stomachs = stomachs
        import __builtin__
        setattr(__builtin__, species, self)

By explicitly using the __builtin__ module, you ensure you can "print thespeciesname" from ANY module -- not just the one defining Zoo, nor just the one instantiating it.

It's STILL a terrible idea, but this is the least-horror way to implement it.

Comments

0
class Zoo(object):
    def __init__(self, name):
        self.name = name
        self.animals = []

    def __str__(self):
        return ("The %s Zoo houses:\n" % self.name) + "\n".join(str(an) for an in self.animals)

class Animal( object ):
    species = None
    def __init__(self, legs, stomach):
        self.legs = legs
        self.stomach = stomach

    def __str__(self):
        return "A %s with %d legs and %d stomachs" % ( self.species, self.legs, self.stomach )


class Bear( Animal ):
    species = "Bear"

class Karp( Animal ):
    species = "Karp"


## this is the point ... you can look up Classes by their names here
## if you wonder show to automate the generation of this dict ... don't.
## ( or learn a lot Python, then add a metaclass to Animal ;-p )
species = dict( bear = Bear,
                karp = Karp )

zoo = Zoo( "Strange" )
while len(zoo.animals) < 9:
    name = raw_input("Enter species name: ").lower()
    if name in species:
        legs = input("How many legs does this species have? ")
        stomachs = input("...and how many stomachs? ")
        zoo.animals.append( species[name]( legs, stomachs ) )
    else:
        print "I have no idea what a", name, "is."
        print "Try again" 

print zoo

Comments

0
>>> class Bear():
...     pass
... 
>>> class Dog():
...     pass
... 
>>> 
>>> types = {'bear': Bear, 'dog': Dog}
>>> 
>>> types['dog']()
<__main__.Dog instance at 0x75c10>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.