My aim is to define a set of classes, each providing methods for comparing a particular type of file. My idea is to use some kind of factory method to instantiate the class based upon a string, which could allow new classes to be added easily. Then it would be simple to loop over a dictionary like:
files = {
'csv': ('file1.csv', 'file2.csv'),
'bin': ('file3.bin', 'file4.bin')
}
Here is what I have so far:
# results/__init__.py
class ResultDiffException(Exception):
pass
class ResultDiff(object):
"""Base class that enables comparison of result files."""
def __init__(self, path_test, path_ref):
self.path_t = path_test
self.path_r = path_ref
def max(self):
raise NotImplementedError('abstract method')
def min(self):
raise NotImplementedError('abstract method')
def mean(self):
raise NotImplementedError('abstract method')
# results/numeric.py
import numpy as np
from results import ResultDiff, ResultDiffException
class NumericArrayDiff(ResultDiff):
def __init__(self, *args, **kwargs):
super(NumericArrayDiff, self).__init__(*args, **kwargs)
self.data_t = self._read_file(self.path_t)
self.data_r = self._read_file(self.path_r)
if self.data_t.shape != self.data_r.shape:
raise ResultDiffException('Inconsistent array shape')
np.seterr(divide='ignore', invalid='ignore')
self.diff = (self.data_t - self.data_r) / self.data_r
both_zero_ind = np.nonzero((self.data_t == 0) & (self.data_r == 0))
self.diff[both_zero_ind] = 0
def _read_file(self, path):
return np.loadtxt(path, ndmin=1)
def max(self):
return np.amax(self.diff)
def min(self):
return np.amin(self.diff)
def mean(self):
return np.mean(self.diff)
class CsvDiff(NumericArrayDiff):
def __init__(self, *args, **kwargs):
super(CsvDiff, self).__init__(*args, **kwargs)
def _read_file(self, path):
return np.loadtxt(path, delimiter=',', ndmin=1)
class BinaryNumericArrayDiff(NumericArrayDiff):
def __init__(self, *args, **kwargs):
super(BinaryNumericArrayDiff, self).__init__(*args, **kwargs)
def _read_file(self, path):
return np.fromfile(path)
As you can see, the classes CsvDiff
and BinaryNumericArrayDiff
have only very minor changes with respect to NumericArrayDiff
, which could potentially be refactored using constructor arguments. The problem is that different file types would then require different constructor syntax, which would complicate the factory pattern.
I did also consider providing @classmethod
s to NumericArrayDiff
, which could be put in a dict
in order to link to the file types. However, I'm hoping for a more natural way of registering these classes to the factory.
Any advice would be much appreciated.