1

This is related to "Extends is evil" vs. OCP? but separate because the idea of "implement the interface" doesn't exist in Python.

I'm writing a class to pull some data off a webpage. It's going to need to hold on to a cookie for authentication, so I'm going to use a requests.Session object in some form. I'm never sure how to approach this -- what's the appropriate choice here?

class FooFetcher(requests.Session):
    def __init__(self):
        super.__init__()

or

class FooFetcher(object):
    def __init__(self):
        self.session = requests.Session()

?

The former seems to end up with FooFetcher having way more public methods than it needs to. The latter looks like it might be unnecessarily convoluted, since pretty much every method of FooFetcher is going to involve a call to a method of that Session object, plus maybe some parsing of JSON that it finds.

Patrick Collins
  • 2,165
  • 18
  • 24
  • Would you like to have-a wallet, or be-a wallet? If you chose have-a than the person should have-a wallet. Should your penguins have-a animal or be-a animal? ...and so on and so forth. – Jimmy Hoffa Sep 13 '13 at 18:58
  • 1
    Fair enough -- it just seems strange to me in the case like this one where the only thing that matters about `FooFetcher` is the session. If the only interaction I have with my parents is to ask them for money, it might make sense to say that they `are-a` wallet rather than `have-a` wallet, from my perspective. – Patrick Collins Sep 13 '13 at 19:03
  • There's no reason you can't implement an interface that provides facilities from the things you *have*, if you have-a wallet, then perhaps the person interface should have a TakeMoney method on it. In fact many institutions presume we do all have this interface method implemented :| – Jimmy Hoffa Sep 13 '13 at 19:05
  • Note that in your first example, the `__init__` method is entirely redundant and can be omitted entirely. – Martijn Pieters Sep 13 '13 at 19:08
  • If _the only thing that matters about `FooFetcher` is the session_, is it even really a class? You can just pass your session into a bunch of free functions, if there's no other state – Useless Sep 13 '13 at 21:13

2 Answers2

3

The trick is to look at the calling code. Is there any code that currently uses a requests.Session object that you want to be able to pass in a FooFetcher instead? If not, then use composition.

Karl Bielefeldt
  • 146,727
  • 38
  • 279
  • 479
1

Your particular example strongly suggests HAS-A relationship, thus, composition, because FooFetcher is not a Session.

BTW, Python does have multiple inheritance, and sometimes functionality can be added using mix-ins.

For example, you may have Sessioning and add it as a mix-in:

 class FooFetcher(BaseFetcher, Sessioning):
     ...

Returning to your second example, I think, session should be explicit:

class FooFetcher(object):
    def __init__(self, session):
        self.session = session

This way it's easier to test and maintain the code.

Roman Susi
  • 1,763
  • 2
  • 12
  • 20