Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Greg Kaleka
Greg Kaleka
39,021 Points

Need help thinking through some object oriented design

I'm building an app that will call various public transportation agencies' APIs and get live data back from them. I'd like to have an Agency model with a method get_arrivals. This method needs to:

  1. Make a call to the agency's API url
  2. Parse the results
  3. Return a list of arrival times and whether they are scheduled or live times

The problem is that 1. and 2. will differ by each agency.

1 isn't a big deal - I can simply set the URL on each Agency instance (although it would be nice to be able to pull in an API key dynamically from an environment variable rather than hard-coding it into the url attribute, so I'm not storing it in the DB).

2, though, I have no idea how to handle parsing differently per agency. I suppose I could use subclassing for each agency to override the method, but that seems messy. I might have hundreds of agencies down the line. I could have a helper method that the get_arrivals method calls. That helper method could take an agency name, and have a bunch of if statements to figure out how to parse the response. That seems doable, but maybe not ideal. That's going to end up being one big function.

Any direction y'all can provide would be much appreciated!!

Since this is a fairly advanced topic, I'm going to ping Kenneth Love to see if he will graciously chime in.

Cheers :beers:

-Greg

2 Answers

Ignazio Calo
PLUS
Ignazio Calo
Courses Plus Student 1,819 Points

Hi I'm a new joiner and I hope you don't mind if I give you my 2cents. About the 1. It's up to you where you want to store the different urls. I would got for a configuration file, like YML/JSON file. On the file you store the name of the agency and the url, then on the code you just need to specify the name of the agency for each instance.

About the 2. I suggest to use composition over subclass. You can create as many parser class you need and assign the specific parser to the specific agency instance. In this way you can reuse the same parser for multiple agencies if you need.

If your question is "how can I know which parser each agency should use", I suggest you to add into your db/conf file the class name of the relative parser.

Greg Kaleka
Greg Kaleka
39,021 Points

Thanks Ignazio! I like that solution a lot.

It seems like I would need an inheritance tree for some kind of abstract Parser class, though, right? That way I can write my Agency class with an attribute of parser with some known behavior like parse_results(), and then subclasses like class ParisMetroParser(Parser) would define the implementation of that method. My instances would be able to set their parser attribute to ParisMetroParser, NYCSubwayParser, etc.

Am I thinking about that correctly? Is there a better way to do that? This feels like a job for protocols (does Python even have those?), but I'm not sure exactly how to pull that off.

(p.s. as a moderator here on the forums, I took the liberty of changing your comment to an answer. You can continue this thread by adding a comment to your answer, and it'll show up below this comment right here.)

Ignazio Calo
Ignazio Calo
Courses Plus Student 1,819 Points

Yes, you're right. You can start with a "default" Parser implementation with a basic implementation of a method like parse_results() and make all the more specialized parser subclass of the first one.

The common problem with this approach is that the "default" Parser can end up to have an empty implementation of the parse_results() because there is no such a thing like a default parser.

In Java this would be solved in a more elegant way with an Interface or an Abstract class. In languages like Objective-C or Swift you could use a Protocol ...unfortunately I'm not a Python dev and I'm not sure if you can have Abstract classes in python.

I found this answer on SO that says is possible, but I let the decision to you. https://stackoverflow.com/questions/13646245/is-it-possible-to-make-abstract-classes-in-python

Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

I think Ignazio Calo is absolutely right with the idea of doing through composition over inheritance (or, likely, a combination of the two). You'd have an Agency class that you may or may not subclass per agency, and you'd give each instance a URL for the feed, etc.

You'd also specify the functions or classes that handle the parsing for each agency. This might be another place where you need more inheritance.