2

I'm trying to create a Python gazetteer module. I have the following classes: State, County, and City. I need a State to know all of its counties, a County to know all of its cities, and a City to know its County & State. (Python 3.x)

Here is what I have:

class State(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def state_name(self):
        return self.state


class County(State):
    def __init__(self, state_class, **kwargs):
        self.__bases__ = (state_class, )
        self.__dict__.update(kwargs)


class City(County):
    def __init__(self, county_class, **kwargs):
        self.__bases__ = (county_class, )
        self.__dict__.update(kwargs)

Then I do:

fl = State(state='Florida', abb='FL', fips='12')
mdc = County(fl, county='Miami-Dade', fips='086')
setattr(fl, 'miami_dade', mdc)
rmd = City(mdc, city='Richmond', fips='60230')
setattr(mdc, 'richmond', rmd)


print(fl.state, fl.abb, fl.fips, fl.miami_dade.county, fl.miami_dade.richmond.city)
# Florida FL 12 Miami-Dade Richmond
print(fl.state_name())
# Florida
print(fl.__dict__)
# {'abb': 'FL', 'miami_dade': <__main__.County object at 0x0000000002C44A20>, 'fips': '12', 'state': 'Florida'}
print(fl.miami_dade.__dict__)
# {'__bases__': (<__main__.State object at 0x000000000358A048>,), 'fips': '086', 'county': 'Miami-Dade', 'richmond': <__main__.City object at 0x0000000002C44A90>}
print(fl.miami_dade.richmond.__dict__)
# {'fips': '60230', 'city': 'Richmond', '__bases__': (<__main__.County object at 0x0000000002C44A20>,)}
print(isinstance(fl.miami_dade.richmond, State))
# True

All good so far... but then:

print(fl.miami_dade.richmond.state_name())
# AttributeError: 'City' object has no attribute 'state'

I want my City class to use methods in the State and County classes. My best guess is that the code print(fl.miami_dade.richmond.state_name()) is executing the state_name() method using the attributes in the City instance and not the attributes in the State instance.

I don't understand what I'm doing wrong here. Is it even possible for a County class to inherit the methods and attributes of a already initialized State class?


More info:
I don't want to do super().__init__() in City and County e.g. a = City('Seattle', 'King', 'Washington') because of the following.
I have data with 56 states (includes US territories), 3,234 counties, and 163,252 cities. It's a waste of memory if I have every City have a copy of its County and State. Also, I have coordinates that form a polygon for every county (~20MB) the average county has ~50 cities; that's over a Gig if every city has a copy.


Ok, this is not a good structure for what I'm doing and I'm changing it but I don't like it when I don't understand something. I want to understand what's going on here.
Here is a simplified version:

class A:
    def __init__(self, name):
        self.name = name

    def getA(self):
        return self.name

class B(A):
    def __init__(self, aname, bname):
        self.name = bname
        super().__init__(aname)

b = B('AAA', 'BBB')
print(b.getA())
# AAA

Ok, I get this just fine. But then here:

class A2:
    def __init__(self, name):
        self.name = name

    def getA2(self):
        return self.name

class B2(A2):
    def __init__(self, A2Obj, name):
        self.__bases__ = (A2Obj, )
        self.name = name

a2 = A2('AAA2')
b2 = B2(a2, 'BBB2')
print(b2.getA2())
# BBB2
print(a2.name)
# AAA2

a2 knows its name is AAA2. Why is b2.getA2() giving me BBB2? It's like b2 inherited the methods of a2 but not the attributes. How do I make b2 behave like the example above?

3
  • It sounds like you want a database with some tables describing the state -> county and county -> city relationships (hence the state -> city, city -> county, and city -> state relationships either by reversing or joining as needed). In memory this would typically be done with some hash tables (dict in Python) or with a set of pandas.DataFrame objects if you want something better at indexed numerical computation. But really, you probably just want to drop your data into a simple set of postgres tables and then use sqlalchemy if you really want classes that represent the entities. Commented Feb 24, 2015 at 23:26
  • Keep in mind that nothing forces you to structure the computations on top of this data in an object oriented way. You are free to just have some dicts that contain the data, and then write helper functions that extract, merge, join, and process the contents of those dicts as needed. Instead of something being StateObj.do_foo_on_city() it can just as easily be do_foo_on_city( get_city_from_state(state_dict, city_dict, *some_other_args)) making it compositional at the functional level, rather than class composition. A lot of numeric code is better off this way. Commented Feb 24, 2015 at 23:30
  • @Mr. F - You're right, there are better ways to do it. I was doing it that way out of curiosity but now it's bothering me that I don't understand what's going on. I edited my question to include a simpler example. Commented Feb 25, 2015 at 2:49

1 Answer 1

4

You likely use the wrong structure : your city is not a county, your county is not a state. You should use composition instead of derivation

class State(object):
  def __init__(self, **kwargs):
    self.__dict__.update(kwargs)

  def state_name(self):
    return self.state


class County(object):
  def __init__(self, state, **kwargs):
    self.state=state # this will just reference the state object
    self.__dict__.update(kwargs)
  def getStateName(self):
    return self.state.state


class City(object):
  def __init__(self, county, **kwargs):
    self.county = county
    self.__dict__.update(kwargs)
  def getStateName(self):
    return self.county.getStateName()

If you want to be able to retrieve them later without keeping track of the objects, you can use a static dictionary and add created object during init (eg "FL" -> State("Florida")). Then add a static method to retrieve the correct object.

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

1 Comment

That's funny - I did the same thing you did there but I made County an inner class of State and City an inner class of County (I tried out a few structures). I updated my question with a simpler example of what I'm trying to understand.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.