简体   繁体   中英

Python | Avoid repeating chunk of code

I have couple of methods inside a class that control a virtual machine life-cycle. Operations like start, stop, terminate, retire .. etc

The code for these methods is almost identical, for example:

def stop(self, instances):
    """
    Stop instance or a group of instances
    :param instances: List of instances
    :return:
    """
    try:
        response = self.ec2_client.stop_instances(InstanceIds=instances, DryRun=False)
        print(response)
    except ClientError as e:
        print(e)

    return response

def start(self, instances):
    """
    Start instance or a group of instances
    :param instances: List of instances
    :return:
    """
    try:
        response = self.ec2_client.start_instances(InstanceIds=instances, DryRun=False)
        print(response)
    except ClientError as e:
        print(e)

    return response

As you can see, the two methods are almost identical except for the API call to perform the required action (start_instances and stop_instance).

Is there is a way to write such methods or functions in general and prevent repeating code?

Thanks in advance.

PS I was thinking of decorators, instance functions, closures -- but just don't know how!


Below answers inspired me to the following solution:

    @staticmethod
def _request_action_method(action, instances):
    instance_ids = FleetManager._instance_to_str(instances)

    def _action_method():
        try:
            response = action(InstanceIds=instance_ids, DryRun=False)
            print(response)
        except ClientError as e:
            print(e)

    return _action_method

I could replace +50 lines of code with those few lines and it works :)

Make a function let's say

@staticmethod
def _request(method, instances):
 try:
    response = method(InstanceIds=instances, DryRun=False)
    print(response)
 except ClientError as e:
    print(e)
 return response

and call them

def stop(self, instances):
  self._request(self.ec2_client.stop_instances, instances)

def start(self, instances):
  self._request(self.ec2_client.start_instances, instances)

You can store a map of of stop: {stop_instances, start: start_instances} and call a single function that does the rest. Use getattr to obtain the member from self.ec2_client by name, or just the whole method.

Pseudo code:

In __init__ :

self.methodmap = {'start': self.ec2_client.start_instances,
                  'stop': self.ec2_client.stop_instances}

Then, for example:

def start(self, instances):
  return self.run('start', instances)

def run(self, command, instances):
  method = self.methodmap[command]
  try:
    response = method(InstanceIds=instances, DryRun=False)
    print(response)
  except ClientError as e:
    print (e)
  return response

Depending on how much flexibility you want, you don't have to define self.methodmap but can also pass the method direction in the invocation of self.run .

For extra magic (be careful!) you can auto-generate the start , stop etc. methods too, because they all follow the same pattern.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM