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.