2

I have a python class which reads a config file using ConfigParser:

Config file:

[geography]
Xmin=6.6
Xmax=18.6
Ymin=36.6
YMax=47.1

Python code:

class Slicer:
    def __init__(self, config_file_name):
        config = ConfigParser.ConfigParser()
        config.read(config_file_name)
        # Rad the lines from the file
        self.x_min = config.getfloat('geography', 'xmin')
        self.x_max = config.getfloat('geography', 'xmax')
        self.y_min = config.getfloat('geography', 'ymin')
        self.y_max = config.getfloat('geography', 'ymax')

I feel that the last four lines are repetitive, and should somehow be compressed to one Pythonic line that would create a self.item variable for each item in the section.

Any ideas?

Adam

UPDATE:

Following your answers, I've modified my code to:

    for item in config.items('geography'):
        setattr(self, '_'+item[0], float(item[1]))

Now,

   print self.__dict__
   >>> {'_xmax': 18.600000000000001, '_ymax': 47.100000000000001, 
        '_ymin': 36.600000000000001, '_xmin': 6.5999999999999996}
Adam Matan
  • 128,757
  • 147
  • 397
  • 562
  • Anyone see great potential for security vulnerabilities with this approach? Imagine some evil intention adding `_dict__=[]` line to your config. If `__dict__` is protected by a chance (I didn't try it in real) then there're plenty more of other `__XXX__` helpers that might get interfered. So, Rubayeet's and Michael's answers are way more perfect as following pythonic principle 'Explicit is better than implicit'. – Van Jone Mar 26 '15 at 00:11

3 Answers3

5

I usually try to avoid external interactions in a constructor - makes it hard to test the code. Better pass a config parser instance or a fp-like object instead of a filename.

Felix Schwarz
  • 2,938
  • 4
  • 28
  • 41
  • 3
    +1: Reading a config is not part of the constructor. Pass the open file to a method. Do not secretly open a file. If you pass an opened file object to a method, you can easily construct a unit test that doesn't secretly depend on a secret file. – S.Lott Apr 11 '10 at 11:47
  • They want your class to function more like `s = Slicer(file); s.parse()`. As opposed to doing it all in the config. It becomes hard to test individual methods and functionality in a unittest, if a lot of the functionality takes place in the init. –  Apr 11 '10 at 11:52
3
for line in ['x_min', 'x_max', 'y_min', 'y_max']:

   setattr(self, line, config.getfloat('geography', line.replace('_', '')))
rubayeet
  • 9,269
  • 8
  • 46
  • 55
1

How about something like:

for key in ['xmin','xmax','ymin','ymax']:
    self.__dict__[key] = config.getfloat('geography',key);

Note that the above will assign it to self.xmin instead of self.x_min... however, if you are fine with that naming, then this should work... otherwise, mapping between names would be more code than the original.

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200