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?
dictin Python) or with a set ofpandas.DataFrameobjects 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.dicts that contain the data, and then write helper functions that extract, merge, join, and process the contents of thosedicts as needed. Instead of something beingStateObj.do_foo_on_city()it can just as easily bedo_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.