0

What would be the best approach to avoid checks in each method.

As seen in below example, check is happening in each and every method to make sure app is either connected or not connected.

Any design patterns or other elegant solution to avoid checks and repetition of the code ?

class App:

    def __init__(self):
        self._is_connected = False

    def connect(self):
        if self._is_connected:
            raise Exception('Already connected')
        pass

    def disconnect(self):
        if not self._is_connected:
            raise Exception('Already disconnected')
        pass

    def send_data(self):
        if not self._is_connected:
            raise Exception('Not connected')
        pass

    def recv_data(self):
        if self._is_connected:
            raise Exception('Not connected')
        pass
Ketan Patel
  • 69
  • 1
  • 5
  • By "avoid checks in each method", do you mean not doing the check or not having to manually code it into each one? – martineau Jun 08 '19 at 00:37
  • ...If you mean the latter, see [How to wrap every method of a class?](https://stackoverflow.com/questions/11349183/how-to-wrap-every-method-of-a-class) – martineau Jun 08 '19 at 00:46
  • I want to do checks but the current approach does not seem too elegant and that probably means there must a better way. Metaclass may not be the right choice since this kind of pattern is going to be there for many kind classes. Thanks :) – Ketan Patel Jun 08 '19 at 01:26
  • Although it may not appear to be related, the accepted answer to the question [How to make built-in containers (sets, dicts, lists) thread safe?](https://stackoverflow.com/questions/13610654/how-to-make-built-in-containers-sets-dicts-lists-thread-safe) discusses many different ways to wrap a class' methods (including metaclasses). – martineau Jun 08 '19 at 01:53

1 Answers1

0

Python's decorators is one way to remove this code duplication. So you can define 2 decorator functions: is_connected and is_disconnected. Within the decorator functions, you can access self to check for the variable. Here's a skeleton of the definition of one of them:

def is_connected(func):
    def wrapper(self, *args, **kwargs):
        # Do the check and raise any errors
        if not self.connected:
            raise ValueError()
        func(*args, **kwargs)
    return wrapper

You would then use them on the functions as so:

@is_disconnected
def connect(self):
    pass

@is_connected
def disconnect(self):
    pass
yanxun
  • 566
  • 2
  • 10
  • 1
    that is not a solution, you still got the code there – user8426627 Jun 08 '19 at 00:44
  • The question specifies to avoid repetition of the code, which is what the decorators are for: reusing code. I might be wrong, but I don't think it is possible to do checks without the code at all. – yanxun Jun 08 '19 at 20:23
  • i guess it should be redesigned to avoid these checks, like have self.connection.send_data, self.connection.recv_data, methods – user8426627 Jun 08 '19 at 20:28
  • Hmm, I don't see how that avoid the checks, as you still need to ensure connectivity within self.connection. So the methods and checks now live within self.connection instead of class App. – yanxun Jun 08 '19 at 20:33
  • idea is, if self.connection is not None the connection is established and the methods works, else you will got an exception accesing to None – user8426627 Jun 08 '19 at 20:41
  • I see now, and agree that works too. Though one thing I don't like about it: you will be catching the None method exception instead of raising and catching your own relevant exception. – yanxun Jun 08 '19 at 21:10