I solved this in my code using "partial application".
Example is written using Python 3, but partial application works the same way in Python 2:
from functools import partial
from http.server import HTTPServer, BaseHTTPRequestHandler
class ExampleHandler(BaseHTTPRequestHandler):
def __init__(self, foo, bar, qux, *args, **kwargs):
self.foo = foo
self.bar = bar
self.qux = qux
# BaseHTTPRequestHandler calls do_GET **inside** __init__ !!!
# So we have to call super().__init__ after setting attributes.
super().__init__(*args, **kwargs)
def do_HEAD(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
def do_GET(self):
self.do_HEAD()
self.wfile.write('{!r} {!r} {!r}\n'
.format(self.foo, self.bar, self.qux)
.encode('utf8'))
# We "partially apply" the first three arguments to the ExampleHandler
handler = partial(ExampleHandler, sys.argv[1], sys.argv[2], sys.argv[3])
# .. then pass it to HTTPHandler as normal:
server = HTTPServer(('', 8000), handler)
server.serve_forever()
This is very similar to a class factory, but in my opinion it has a couple of subtle advantages:
partial
objects are much easier to introspect for what's inside them than nested classes defined and returned by factory functions.
partial
objects can be serialized with pickle
in modern Python, whereas nested class definitions inside factory functions cannot (at least not without going out of your way to code a __reduce__
method on the class to make it possible).
- In my limited experience explicit "pre-attaching" of arguments with
partial
to an otherwise Pythonic and normal class definition is easier (less cognitive load) to read, understand, and verify for correctness than a nested class definition with the parameters of the wrapping function buried somewhere inside it.
The only real disadvantage is that many people are unfamiliar with partial
- but in my experience it is better for everyone to become familiar with partial
anyway, because partial
has a way of popping up as an easy and composable solution in many places, sometimes unexpectedly, like here.