0

I have a superclass that looks like:

class Channel:
    def __init__(self):
        # Mutual preparation stuff
        self.some_computational_expensive_method()

    def run(self, conf, method="tcp"):
        if method == "tcp":
            return self.run_as_tcp(conf)
        elif method == "udp":
            return self.run_as_udp(conf)
        else:
            raise ValueError

And I want to define some child (simplified versions) classes that overrides de run method to return either run_as_tcp or run as udp, like:

class TCPChannel(Channel):
    def run(self, conf):
        return self.run_as_tcp(conf)

class UDPChannel(Channel):
    def run(self, conf):
        return self.run_as_udp(conf)

But if I do that (override the method), I am not matching the run signature of the Channel class. Is there a pythonic way to do this?

EDIT: There is a reason to have the superclass. In a previous stage (some_computational_expensive_method) some operations are performed. So if I want to try both run methods (as_udp and as_tcp) I don't want to create two separate objects (TCPChannel and UDPChannel) and use their own run methods, because that will run the expensive task . Instead, I want to create a Channel object and use run method twice with different argument.

But if I don't want to have UDP functionalities, I will use the reduced version, ' TCPChannel`.

Alberto Castaño
  • 186
  • 5
  • 16
  • Check this out. http://stackoverflow.com/questions/10202938/how-do-i-use-method-overloading-in-python – Prajwal Dec 01 '16 at 09:09
  • 2
    But why would you want to do this? Why use inheritance here? It seems like `Channel` is already designed to do everything you need. – juanpa.arrivillaga Dec 01 '16 at 09:15
  • @juanpa.arrivallaga I need to code an API and I need to define that, lets say, "meta" class and then some specific methods classes. I know it sounds weird, but I need to do it. – Alberto Castaño Dec 01 '16 at 09:20
  • @Prajwal Thank you for the answer, but I don't really find an answer that fits my problem there. – Alberto Castaño Dec 01 '16 at 09:22
  • I don't understand your edit, do you mean that expensive method calls run twice - once for each method? – Sayse Dec 01 '16 at 09:39
  • @Sayse Nope, I mean that if I want to try both `run` methods (as_udp and as_tcp) I don't want to create two separate objects (`TCPChannel` and `UDPChannel`) and use their own `run` methods, because that will run twice the expensive task. Instead, I want to create a `Channel` object and use `run` twice. – Alberto Castaño Dec 01 '16 at 09:43
  • I've updated my answer... I don't think a random value will help here – Sayse Dec 01 '16 at 09:48
  • 1
    I was about to suggest to use `super()` in the sublcasses and declare their `run` methods with the very same signature as their parent's, passing the `method` param to the superclass', but the whole thing just doesn't seem right, for a number of reasons. Probably you aren't adopting the right OO design approach to the problem. Research some more and/or describe what the driving goal is. Thank you. – Pynchia Dec 01 '16 at 09:55

3 Answers3

0

It sounds to me like the base class shouldn't ever need to have an if statement in it.

class Channel:
    def run(self, conf):
        raise ValueError

class TCPChannel(Channel):
    def run(self, conf):
        return self.run_as_tcp(conf)

class UDPChannel(Channel):
    def run(self, conf):
        return self.run_as_udp(conf)

I'd imagine that theres not much need for a tcp to ever run as udp so the overriden classes should contain the logic for running as the type of channel it is

Based on your edit, I don't think its a good idea to try and give some random value for that function, the above solution should still work, but your expensive method should call run_as_tcp and run_as_udp directly.

Sayse
  • 42,633
  • 14
  • 77
  • 146
  • Edited to reply you. Thanks. – Alberto Castaño Dec 01 '16 at 09:36
  • I don't understand you. It will not be a random value. I have edited again, I hope it is more clear. – Alberto Castaño Dec 01 '16 at 09:52
  • @AlbertoCastaño - Sorry, thats probably a loss in translation of my own terminology... What I meant is that the "random value" would end up just being something like `run_method = run_as_udp` then your channel run would just do `return self.run_method(conf)` but then wherever you'd use it you'd have to import the method, it would probably be cleaner just to call the methods directly – Sayse Dec 01 '16 at 09:53
0

If you don't invoke the Channel's run method itself you could do something like

class Channel:
    def run(self, conf):
        raise NotImplementedError

class TCPChannel(Channel):
    def run(self, conf):
        return self.run_as_tcp(conf)

class UDPChannel(Channel):
    def run(self, conf):
        return self.run_as_udp(conf)
Maarten Fabré
  • 6,938
  • 1
  • 17
  • 36
-1

You can match the signature and still check for consistent usage. For example:

class TCPChannel(Channel):
    def run(self, conf, method='tcp'):
        assert(method=='tcp')
        return self.run_as_tcp(conf)

class UDPChannel(Channel):
    def run(self, conf, method='udp'):
        assert(method=='udp')
        return self.run_as_udp(conf)
cco
  • 5,873
  • 1
  • 16
  • 21
  • I'll take it as an option. However, would be possible to "hide" the method argument from the user? I mean, from the programmer – Alberto Castaño Dec 01 '16 at 09:25
  • Not if matching the signature is a requirement (which I took it to be). If you don't want that argument visible, one of the other suggestions might be preferable. – cco Dec 01 '16 at 09:37