Two patterns which you can refactor towards are Strategy and Decorator.
The Decorator Pattern is often implemented in Python using context managers. There is a library to make them easier to implement, contextlib:
from contextlib import contextmanager @contextmanager def get_file(filename): # some generic code for opening the file etc. yield # some generic code for closing the file etc.
The yield statement enables you to inject whatever you want while you're in the with block:
with get_file(filename) as resource: get_file_ftp(resource)
or:
with get_file(filename) as resource: get_file_tftp(resource)
The with block will ensure the statements after the yield are executed, even in the presence of exceptions.
Another way of implementing decorators is with Python's decorator syntax. I suggested a context manager because I thought you wanted before and after statements whatever happened in between. Python's decorator syntax would make you have to implement the exception handling yourself. The decorator modifies the function
def get_file(function): def generic_code(filename): ... # some generic code for opening the file etc. function(filename) ... # some generic code for closing the file etc. return generic_code
Usage:
@get_file def get_file_ftp(filename): ... # ftp-specific code
Alternatively, with the Strategy Pattern, you'd pass the strategy for handling different file sources into the get_file function:
def get_file(filename, file_strategy): # some generic code for opening the file etc. file_strategy(filename) # some generic code for closing the file etc.
Then use it like:
get_file(filename, get_file_ftp)
or:
get_file(filename, get_file_tftp)
get_file_ftp, instead of themode.