Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can I apply a prefix to dictionary access?
    text
    copied!<p>I'm imitating the behavior of the <code>ConfigParser</code> module to write a highly specialized parser that exploits some well-defined structure in the configuration files for a particular application I work with. Several sections of the config file contain hundreds of variable and routine mappings prefixed with either <code>Variable_</code> or <code>Routine_</code>, like this:</p> <pre><code>[Map.PRD] Variable_FOO=LOC1 Variable_BAR=LOC2 Routine_FOO=LOC3 Routine_BAR=LOC4 ... [Map.SHD] Variable_FOO=LOC1 Variable_BAR=LOC2 Routine_FOO=LOC3 Routine_BAR=LOC4 ... </code></pre> <p>I'd like to maintain the basic structure of <code>ConfigParser</code> where each section is stored as a single dictionary, so users would still have access to the classic syntax:</p> <pre><code>config.content['Mappings']['Variable_FOO'] = 'LOC1' </code></pre> <p>but also be able to use a simplified API that drills down to this section:</p> <pre><code>config.vmapping('PRD')['FOO'] = 'LOC1' config.vmapping('PRD')['BAR'] = 'LOC2' config.rmapping('PRD')['FOO'] = 'LOC3' config.rmapping('PRD')['BAR'] = 'LOC4' </code></pre> <p>Currently I'm implementing this by storing the section in a special subclass of <code>dict</code> to which I've added a <code>prefix</code> attribute. The <code>variable</code> and <code>routine</code> properties of the parser set the <code>prefix</code> attribute of the <code>dict</code>-like object to <code>'Variable_'</code> or <code>'Routine_'</code> and then modified <code>__getitem__</code> and <code>__setitem__</code> attributes of the <code>dict</code> handle gluing the prefix together with the key to access the appropriate item. It's working, but involves a lot of boilerplate to implement all the associated niceties like supporting iteration.</p> <p>I suppose my ideal solution would be do dispense with the subclassed <code>dict</code> and have have the <code>variable</code> and <code>routine</code> properties somehow present a "view" of the plain <code>dict</code> object underneath without the prefixes.</p> <h2>Update</h2> <p>Here's the solution I implemented, largely based on @abarnet's answer:</p> <pre><code>class MappingDict(object): def __init__(self, prefix, d): self.prefix, self.d = prefix, d def prefixify(self, name): return '{}_{}'.format(self.prefix, name) def __getitem__(self, name): name = self.prefixify(name) return self.d.__getitem__(name) def __setitem__(self, name, value): name = self.prefixify(name) return self.d.__setitem__(name, value) def __delitem__(self, name): name = self.prefixify(name) return self.d.__delitem__(name) def __iter__(self): return (key.partition('_')[-1] for key in self.d if key.startswith(self.prefix)) def __repr__(self): return 'MappingDict({})'.format(dict.__repr__(self)) class MyParser(object): SECTCRE = re.compile(r'\[(?P&lt;header&gt;[^]]+)\]') def __init__(self, filename): self.filename = filename self.content = {} lines = [x.strip() for x in open(filename).read().splitlines() if x.strip()] for line in lines: match = re.match(self.SECTCRE, line) if match: section = match.group('header') self.content[section] = {} else: key, sep, value = line.partition('=') self.content[section][key] = value def write(self, filename): fp = open(filename, 'w') for section in sorted(self.content, key=sectionsort): fp.write("[%s]\n" % section) for key in sorted(self.content[section], key=cpfsort): value = str(self.content[section][key]) fp.write("%s\n" % '='.join([key,value])) fp.write("\n") fp.close() def vmapping(self, nsp): section = 'Map.{}'.format(nsp) return MappingDict('Variable', self.content[section]) def rmapping(self, nsp): section = 'Map.{}'.format(nsp) return MappingDict('Routine', self.content[section]) </code></pre> <p>It's used like this:</p> <pre><code>config = MyParser('myfile.cfg') vmap = config.vmapping('PRD') vmap['FOO'] = 'LOC5' vmap['BAR'] = 'LOC6' config.write('newfile.cfg') </code></pre> <p>The resulting <code>newfile.cfg</code> reflects the <code>LOC5</code> and <code>LOC6</code> changes.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload