Search code examples
pythonpython-decorators

Python coding technique: class methods that use another method as interface to do system calls


Is there a way to better implement my code leveraging python coding techniques considering that I have a few methods that are all wrapping one specific method and adding a bit of pre/post processing to it?

Looking to leverage python coding techniques (thinking python decorators might help clean this a bit) to implement the class below.

I have a class that has one method to interface with the outside world and that other methods in the class use to execute actions and do pre/post processing of some data.

import subprocess as sp


class MyClass():

    def _system_interface(self, command):
        hello = ["echo", "'hello'"]
        start = ["echo", "'start'"]
        stop = ["echo", "'reset'"]
        reset = ["echo", "'reset'"]

        cmd = sp.Popen(locals()[command], stdout=sp.PIPE)
        output = cmd.stdout.readlines()
        print(output)
        return cmd.stdout.readlines()

    def call_one(self):
        # Do some processing
        self._system_interface("hello")

    def call_two(self):
        # Do some processing
        self._system_interface("start")

    def call_three(self):
        # Do some processing
        self._system_interface("stop")

    if __name__ == "__main__":
        c = MyClass()
        c.call_one()
        c.call_two()
        c.call_three()

Solution

  • You can use a class that takes a command when instantiated, and when called, returns a decorator function that calls Popen with a command derived from the command given during the instantiation:

    import subprocess as sp
    
    class system_interface:
        def __init__(self, command):
            self.command = command
    
        def __call__(self, func):
            def wrapper(*args, **kwargs):
                func(*args, **kwargs)
                cmd = sp.Popen(['echo', self.command], stdout=sp.PIPE)
                output = cmd.stdout.readlines()
                print(output)
                return cmd.stdout.readlines()
    
            return wrapper
    
    class MyClass():
        @system_interface('hello')
        def call_one(self):
            print('one: do some processing')
    
        @system_interface('start')
        def call_two(self):
            print('two: do some processing')
    
        @system_interface('stop')
        def call_three(self):
            print('three: do some processing')
    
    if __name__ == "__main__":
        c = MyClass()
        c.call_one()
        c.call_two()
        c.call_three()
    

    This outputs:

    one: do some processing
    [b'hello\n']
    two: do some processing
    [b'start\n']
    three: do some processing
    [b'stop\n']