using exec() to instantiate a new object.

Discussion in 'Python' started by RyanN, Nov 7, 2008.

  1. RyanN

    RyanN Guest

    Hello,

    I'm trying to teach myself OOP to do a data project involving
    hierarchical data structures.

    I've come up with an analogy for testing involving objects for
    continents, countries, and states where each object contains some
    attributes one of which is a list of objects. E.g. a country will
    contain an attribute population and another countries which is a list
    of country objects. Anyways, here is what I came up with at first:

    class continent(object):
    def __init__(self,continent_name):
    self.name = continent_name
    self.countries = []
    def addCountry(self,country_name):
    self.countries.append(country_name)
    def listCountries(self):
    for country in self.countries:
    print country.name, "pop:",country.population,", states:"
    country.listStates()

    class country(object):
    def __init__(self,name):
    self.name = name
    self.population = 0
    self.states = []
    def addState(self,state_name):
    self.states.append(state_name)

    def listStates(self):
    for state in self.states:
    print " ",state.name,"pop:",state.population
    state.stateInfo()

    class state(object):
    def __init__(self,state_name):
    self.name = state_name
    self.color = 'unknown'
    self.counties = []
    self.population = 0
    def addCounty(self,county):
    self.counties.append(county)
    def stateInfo(self):
    print " color:",self.color
    print " counties",self.counties[:]


    NAm = continent('NAm')
    usa= country('usa')
    canada = country('canada')
    mexico = country('mexico')
    florida = state('florida')
    maine = state('maine')
    california = state('california')
    quebec = state('quebec')

    NAm.addCountry(usa)
    NAm.addCountry(canada)
    NAm.addCountry(mexico)
    usa.addState(maine)
    usa.addState(california)
    usa.addState(florida)
    canada.addState(quebec)
    florida.addCounty('dade')
    florida.addCounty('broward')
    maine.addCounty('hancock')
    california.addCounty('marin')

    florida.population = 1000
    california.population = 2000
    maine.population = 500
    quebec.population = 1000
    florida.color = maine.color = california.color = 'blue'
    NAm.listCountries()

    --------------------------------------------------------------------------
    so this works but is far more cumbersome than it should be.
    I would like to create an object when I add it

    so I wouldn't have to do:
    usa= country('usa')
    NAm.addCountry(usa)

    I could just do
    NAm.addCountry('usa')

    which would first create a country object then add it to a countries
    list

    to do this I tried:

    def addCountry(self,country_name):
    # create an instance of country
    exec(country_name + "= country('" + country_name + "')")
    # Add this new instance of a country to a list
    exec("self.countries.append(" + country_name + ")")

    Which doesn't give an error, but doesn't seem to create an instance of
    the country object.

    Does this make sense? Can this be done?
    For my real project, I won't know the names and quantities of objects.
    They will be highly variable and based on data contained in the
    "parent" object.

    Thanks
    RyanN, Nov 7, 2008
    #1
    1. Advertising

  2. On Fri, Nov 7, 2008 at 2:23 PM, RyanN <> wrote:

    >
    > to do this I tried:
    >
    > def addCountry(self,country_name):
    > # create an instance of country
    > exec(country_name + "= country('" + country_name + "')")
    > # Add this new instance of a country to a list
    > exec("self.countries.append(" + country_name + ")")
    >


    Don't use exec. It's quite dangerous, and in your case is making
    things much more complex than necessary. A much simpler way to do
    what you want:

    def addCountry(self,country_name):
    self.countries.append(country(country_name))

    There is no need to bind the result of "country(country_name)" to a name at all.
    Patrick Mullen, Nov 8, 2008
    #2
    1. Advertising

  3. RyanN

    Aaron Brady Guest

    On Nov 7, 4:23 pm, RyanN <> wrote:
    > Hello,
    >
    > I'm trying to teach myself OOP to do a data project involving
    > hierarchical data structures.
    >
    > I've come up with an analogy for testing involving objects for
    > continents, countries, and states where each object contains some
    > attributes one of which is a list of objects. E.g. a country will
    > contain an attribute population and another countries which is a list
    > of country objects. Anyways, here is what I came up with at first:

    snip
    >
    > NAm = continent('NAm')
    > usa= country('usa')
    > canada = country('canada')
    > mexico = country('mexico')
    > florida = state('florida')
    > maine = state('maine')
    > california = state('california')
    > quebec = state('quebec')
    >
    > NAm.addCountry(usa)
    > NAm.addCountry(canada)
    > NAm.addCountry(mexico)
    > usa.addState(maine)
    > usa.addState(california)
    > usa.addState(florida)
    > canada.addState(quebec)
    > florida.addCounty('dade')
    > florida.addCounty('broward')
    > maine.addCounty('hancock')
    > california.addCounty('marin')

    snip

    > so this works but is far more cumbersome than it should be.
    > I would like to create an object when I add it
    >
    > so I wouldn't have to do:
    > usa= country('usa')
    > NAm.addCountry(usa)
    >
    > I could just do
    > NAm.addCountry('usa')
    >
    > which would first create a country object then add it to a countries
    > list

    snip

    One option is to add the names to a blank object as attributes, using
    setattr. Then you can access them in almost the same way... they're
    just in their own namespace. Other options would be to add them to a
    separate dictionary (name -> object). This example is kind of cool,
    as well as nicely instructive.

    >>> class Blank: pass

    ....
    >>> blank= Blank()
    >>> class autoname( ):

    .... def __init__( self, name ):
    .... setattr( blank, name, self )
    .... self.name= name
    ....
    >>> autoname( 'fried' )

    <__main__.autoname instance at 0x00B44030>
    >>> autoname( 'green' )

    <__main__.autoname instance at 0x00B44148>
    >>> autoname( 'tomatoes' )

    <__main__.autoname instance at 0x00B44170>
    >>> blank.fried

    <__main__.autoname instance at 0x00B44030>
    >>> blank.green

    <__main__.autoname instance at 0x00B44148>
    >>> blank.tomatoes

    <__main__.autoname instance at 0x00B44170>
    >>> blank

    <__main__.Blank instance at 0x00B40FD0>

    You don't have to call the container object 'blank', of course, or its
    class for that matter. I do because that's how it starts out: blank.
    Under the hood it's just a plain old dictionary with extra syntax for
    accessing its contents.
    Aaron Brady, Nov 8, 2008
    #3
  4. RyanN

    RyanN Guest

    Thank you both, I knew there had to be a good way of doing this.

    -Ryan
    RyanN, Nov 10, 2008
    #4
  5. RyanN

    RyanN Guest

    On Nov 10, 7:47 am, RyanN wrote:
    > Thank you both, I knew there had to be a good way of doing this.
    >
    > -Ryan


    Just an update. I used dictionaries to hold objects and their names.
    I'm beginning to understand better. Now to apply this to my actual
    problem. Here's the code I ended up with:

    class continent(object):
    '''
    A continent has a name and a dictionary of countries
    '''
    def __init__(self,continent_name):
    self.name = continent_name
    self.countries = {} #countries is a dictionary of country name
    and object
    def addCountry(self,country_name,population = 0):
    self.countries[country_name] = country(country_name) #Create a
    new instance of country() and add it to dictionary
    self.countries[country_name].population = population #Set
    country population
    def addState(self,country_name,state_name,population = 0):
    if country_name in self.countries:

    self.countries[country_name].addState(state_name,population)
    else: #This state must be in a new country
    self.addCountry(country_name)
    self.addState(country_name,state_name,population)
    def listCountries(self):
    for a_country in self.countries:
    print a_country,
    "pop:",self.countries[a_country].population,", states:"
    self.countries[a_country].listStates()

    class country(object):
    '''
    A country has a name, a population and a dictionary of states
    '''
    def __init__(self,name):
    self.name = name
    self.population = 0
    self.states = {} #states is a dictionary of state name and
    object
    def addState(self,state_name,population = 0):
    self.states[state_name] = state(state_name) #Create a new
    instance of state() and add it to dictionary
    self.states[state_name].population = population
    self.population += population #Add this state's population to
    the country's

    def listStates(self):
    #print self.states[:]
    for a_state in self.states:
    self.states[a_state].stateInfo()

    class state(object):
    '''
    A state has a name, color, and a population
    '''
    def __init__(self,state_name):
    self.name = state_name
    self.color = 'unknown'
    self.population = 0
    def stateInfo(self):
    print " ",self.name,"pop:",self.population,
    "color:",self.color

    #Now some examples of how to set and access this information
    NAm = continent('NAm') #First we add our continent
    NAm.addCountry('canada',700) #Now add a a country to NAm
    NAm.addState('usa','maine',400) #We can add a state even if we haven't
    added the country yet
    NAm.addState('usa','california',2000)
    NAm.addState('canada','quebec',700) # I know it's actually a province
    NAm.addState('mexico','QR',550)
    usa = NAm.countries['usa'] # we can make things easier on ourselves
    usa.population = 5000 #short for: NAm.countries['usa'].population =
    5000
    usa.addState('florida') #Another way to add a state, we can set
    population seperately
    NAm.countries['usa'].states['florida'].population = 2000
    for any_state in usa.states: #Set an attribute for all state objects
    usa.states[any_state].color = 'blue'
    NAm.listCountries() # Generates a report
    # three ways to get to print the same information
    print NAm.countries['usa'].states['maine'].name,
    NAm.countries['usa'].states['maine'].population
    print usa.states['maine'].name, usa.states['maine'].population # We
    already assigned usa to NAm.countries['usa']
    maine = usa.states['maine']
    print maine.name, maine.population
    RyanN, Nov 10, 2008
    #5
  6. On Nov 10, 10:37 am, RyanN <> wrote:

    > On Nov 10, 7:47 am, RyanN wrote:
    >
    > > Thank you both, I knew there had to be a good way of doing this.

    >
    > > -Ryan

    >
    > Just an update. I used dictionaries to hold objects and their names.
    > I'm beginning to understand better. Now to apply this to my actual
    > problem. Here's the code I ended up with:


    That's fine, but unless you add functionality that *does* actually
    something with all these data, there's not much value going with an
    OO approach compared to using plain old data structures (e.g.
    [default]dicts and [named]tuples).

    George
    George Sakkis, Nov 10, 2008
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Hal Vaughan
    Replies:
    11
    Views:
    1,108
    Gordon Beaton
    May 22, 2006
  2. tedsuzman
    Replies:
    2
    Views:
    7,082
    Michel Claveau, résurectionné d'outre-bombe inform
    Jul 21, 2004
  3. Ted
    Replies:
    1
    Views:
    464
    Duncan Booth
    Jul 22, 2004
  4. tom forsmo
    Replies:
    8
    Views:
    467
    Daniel Pitts
    Apr 18, 2007
  5. Guillermo Riojas
    Replies:
    0
    Views:
    170
    Guillermo Riojas
    Nov 26, 2010
Loading...

Share This Page