looking for a pattern to change function behaviour by context

Zhang Weiwu tristan at realss.com
Fri Nov 1 03:43:07 CET 2013


Problem:

library method request() requests data from external server. Sometimes, if a 
request is failed, it should be ignored, like price inquiry - if we don't 
get the price, then no decision could be made based on the price, then we 
simply do nothing about it; Sometimes, if a request is failed, it should 
retry, and if retry failed, it should throw an exception, like the case with 
placing order.

The problem is how to write the retry/exception code once only, not 
everywhere when needed.

Solution:

1. Inheritance. Add a new parameter 'critical' to the inherited method:

class New(requests.Session): # inherit a library class
 	def request(self, *args, critical = False, *kwargs):
 		if not critical:
 			return super().request(*args, *kwargs)
 		else:
 			result = super().request(*args, *kwargs)
 			if result.status_code != 200: # unsuccessful
 				result = super().request(*args, *kwargs)
 				if result.status_code != 200: # unsuccessful
 					raise SpecificException()
 			return result

class BusinessLogic:
 	....
 	def place_order(self, *args):
 		...
 		server.request(method, URL, critical = True)

Disadvantage: sometimes request is not called directly. The business logic 
class may call other wrappers of request() (e.g. post() and get()), thus we 
need repeat the above code to all the wrappers.

2. Use method 1, and also use decorator to add 'critical' paramter to all 
wrappers of request()

class New(requests.Session): # inherit a library class
 	def AddCriticalParamter(func):
 		.... # add an optional parameter 'critical', which, if set,
 		.... # cause to retry and exception to func

 	@New.AddCriticalParameter
 	def get(self, *args, critical = False, *kwargs):
 		return super().request(*args, *kwargs)

 	@New.AddCriticalParameter
 	def post(self, *args, critical = False, *kwargs):
 		return super().request(*args, *kwargs)

class BusinessLogic:
 	....
 	def place_order(self, *args):
 		...
 		server.get(method, URL, critical = True)

3. Use a wrapper class in business logic

class New(requests.Session): # inherit a library class
 	def Critical(func):
 		.... # change behavior, add retry and exception to func

class BusinessLogic: ....
 	def place_order(self, *args):
 		...
 		critical(server.get)(method, URL)


4. Any other method?

Question is: 1) am I thinking along the right line? and 2) what method will 
you use/recommend?



More information about the Python-list mailing list