1

I am looking for an elegant solution for the following (generic) problem. I want to implement several protocols to access files. Let's say ftp and tftp. More may be added in the future. Right now i'm doing:

get_file(filename): # some generic code for opening the file etc. if mode == 'ftp': get_file_ftp(filename) else: get_file_tftp(filename) # some generic code for closing the file etc. get_file_ftp(filename): # ftp-specific code get_file_tftp(filename): # tftp-specific code 

Same for put_file(), ls() and a dozen more funtions. As code grows, this is starting to get ugly. So my question is: Is there a more clever way to get the job done? Is thera a design pattern that makes sense for this use case? If so, how would i accomplish this in Python?

2
  • 4
    Well, it's the Strategy Pattern. You could pass the function, e.g. get_file_ftp, instead of the mode. Commented Feb 25, 2016 at 11:25
  • 1
    Alternatively, it's the Decorator Pattern. A common way of doing this in Python, particularly with resources, is to use a context manager. Commented Feb 25, 2016 at 11:29

1 Answer 1

1

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) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.