Reputation: 113
I have a class that provides a simple interface to an API. I want to define a method on that class for each route.
Since most of the routes are the same, a lot of the functionality can be factored out into a more generic function, with many routes just being a partially-applied version of this function
class MyAPIWrapper:
def _get_results(self, route, **params):
# Do the important stuff here
results = ...
return results
def get_customers(self):
return self._get_results(self, 'customers')
def get_transactions(self):
return self._get_results(self, 'transactions')
# etc, etc, etc
However, it is apparent that this still results in a fair amount of boilerplate in the class definition.
One alternative is to add a new method that adds each route's method programmatically:
import functools
class MyAPIWrapper:
def __init__(self):
self._init_route_methods()
def _get_results(self, route, **params):
# Do the important stuff here
results = ...
return results
def _init_route_methods(self):
for route in ['customers', 'transactions', ...]:
route_fn = functools.partial(self. _get_results, route)
setattr(self, f'get_{route}', route_fn)
This has the advantage of reducing the amount of boilerplate and makes it easy to add/remove routes. However, adding the methods at initialisation feels somewhat inelegant to me.
Is there a better and/or more idiomatic way to do this?
Upvotes: 1
Views: 292
Reputation: 6789
You may be surprised that this will do the trick:
class MyAPIWrapper:
def _get_results(self, route, **params):
# Do the important stuff here
return route
for route in ['customers', 'transactions']:
exec("""
def get_{0}(self):
return self._get_results('{0}')
""".strip().format(route))
MyAPIWrapper().get_customers() # return customers
MyAPIWrapper().get_transactions() # return transactions
Please note that exec
has a little overhead than setattr(MyAPIWrapper,'get_%s'%route, ...)
, which only matters if you're going to create millions of methods in the loop.
If you want to do the same thing to many different APIWrapper classes, consider to use a class decorator instead.
Upvotes: 2