4

I need to define some key-value parameters to configure the behaviour of a class. My requirements are two:

  • To be able to process them programatically
  • To be able to make more specific configurations that overwrite some of the values.

The natural approach for the first requirement is to use a dict (so I can loop over keys, values or items with a for loop), but for the second requirement it seems more appropriate to use a class hierarchy and let the attribute lookup mechanism to do the work (plus I get other goodies like being able to use properties for some values).

Is there a way to get best of both worlds?


After reading the comments, It does not need to be mutable (I won't be changing the values of an already created instance), it's just for static configuration. But I might need to add new values in a more specific instance.

I think in the end I could just use a dict.copy + dict.update for the specific instances (I can live without the properties).

fortran
  • 74,053
  • 25
  • 135
  • 175
  • 1
    [maybe create a subclass of dict?](http://stackoverflow.com/questions/2390827/how-to-properly-subclass-dict-and-override-get-set) – Fábio Diniz Dec 09 '11 at 13:21
  • For completeness' sake, you could also define a [`__getattr__`](http://docs.python.org/reference/datamodel.html#object.__getattr__) method on your class, but that won't solve the iteration requirement. – Fred Foo Dec 09 '11 at 13:35
  • Is it _instances_ or _subclasses_ of your class that are overriding/adding configuration options? And are these options statically defined, or set dynamically? – ekhumoro Dec 09 '11 at 15:39
  • @ekhumoro as you know, the difference between instances and classes in python is subtle (as classes are already objects), so I really don't care if I achieve this with one class and different instances or subclassing a base class and not making a single instance of any of them. – fortran Dec 09 '11 at 15:51
  • Since your requirements are so loosely defined, it's hard to give a better answer than just `dict(config, **overrides)`. – ekhumoro Dec 09 '11 at 17:50

5 Answers5

2

Somehow along the lines of what suggested in the commment by Fabio, I would remark that the two are not mutually exclusive, given that in Python [nearly] everything is an object (including classes!).

One obvious solution is - again quoting Fabio - subclassing a dict. The other would be make your own class starting from the collections.abc containers (using an abstract base class (abc) is not a requirement, but would probably the most pythonic way to implement your own container from scratch).

HTH!

mac
  • 42,153
  • 26
  • 121
  • 131
1

If you can use python 3.3 ChainMap is exactly what you want.

http://docs.python.org/3.3/library/collections#collections.ChainMap

It's basically a list of dictionaries and will look for a given key in each one sequentially until a match is found.

Actually, here's the code to use it in 2.7:

http://code.activestate.com/recipes/305268-chained-map-lookups/

Aaron McMillin
  • 2,532
  • 27
  • 42
1

is this what you need?

class my_dict(dict):
    def __getattr__(self, name):
        return self[name]
    def __setattr__(self, name, value):
        self[name] = value

d = my_dict()
d.key = "value"
print d.key       #>>>value

for k,v in d.items():
    print k,v     #>>>key value
zchenah
  • 2,060
  • 16
  • 30
1

You could just use named tuples. See here and the accepted answer on this question for a nice introduction to them. Some important points from that answer are:

  • They were added in Python 2.6 and Python 3.0, although there is a recipe for implementation in Python 2.4.

  • Named tuples are backwards compatible with normal tuples

Also, named tuples have a number of useful methods such as _fields to get the names of the used and an _asdict method which returns an (ordered) dict of the named tuple contents.

Community
  • 1
  • 1
Chris
  • 44,602
  • 16
  • 137
  • 156
  • Without the OP clarifying a bit with an example it's difficult to say this for sure, (= I might be wrong!) but I take it that the *"To be able to make more specific configurations that overwrite some of the values"* part of the question means that whatever he will end up using, it will have to be something mutable... and named tuples aren't. :-/ – mac Dec 09 '11 at 14:09
  • @mac You're right, I was just thinking about the construction of a configuration structure with named fields, like [argparse.Namespace](http://docs.python.org/dev/library/argparse.html#argparse.Namespace), assuming that it would be set and then used, not changed. – Chris Dec 09 '11 at 14:14
0

Here's my take:

class Config(object):
    def _keys(self):
        return (name for name in dir(self) if not name.startswith('_'))
    __iter__ = _keys

    def _values(self):
        return (getattr(self, name) for name in self)

    def _items(self):
        return ((name, getattr(self, name)) for name in self)

>>> class Foo(Config):
...     bar = 3
...     baz = 'spam'
...
>>> class Sub(Foo):
...     bar = 4
...
>>> x = Sub()
>>> list(x._items())
[('bar', 4), ('baz', 'spam')]
>>>
yak
  • 8,851
  • 2
  • 29
  • 23