2

This is poor programming practice, yes, I know, but these scripts are purely mine and this technique would ease my coding a lot.

Right now, I have an SQLite database containing a set of key-value pairs representing configuration directives for my script. The script itself is a class which I import into other scripts.

So, right now, when I want to access a config variable, I call something like:

myLib.myClass.getConfigVariable("theItemIWant")

This gets really ugly when using config variables in scripts.

So I want to simplify the access to these variables. I could use a dictionary, that is pre-populated when the class is loaded and do:

myLib.myClass.config['theItemIWant']

But I was thinking even a bit more elegantly. I wrote a separate Config class that I'd like to offer variable-level access to the config entries.

So what I want to be able to do is:

myLib.Config().theItemIWant

Or to instantiate an object in a script like this:

def myRoutine(self):
    cfg = myLib.Config()
    print cfg.theItemIWant

I've read about ugly (using exec) ways to accomplish this, and I'm actually OK with that, but I can't figure out how to set CLASS level variables this way. Most people suggest either using exec or altering either vars or globals, but I am not sure if this will accomplish setting the variables directly on the Config class and not somewhere else.

Using exec failed:

SyntaxError: unqualified exec is not allowed in function '__init__' it contains a nested function with free variables

So the only way I see to do it is to alter vars() but I'm not sure how this applies to classes.

Marcin
  • 48,559
  • 18
  • 128
  • 201
fdmillion
  • 4,823
  • 7
  • 45
  • 82
  • It's not clear what you want to do, or why you would want to use `exec`, not least because you don't show a complete example. If you want to set a member variable, just set it. – Marcin May 01 '13 at 17:27
  • Can you give an example of your code using `exec`? It's not clear what you're trying to achieve. Why can't you just do `myLib.config.theItemIWant = whatever`? – BrenBarn May 01 '13 at 17:27
  • possible duplicate of [Creating dynamically named variables from user input](http://stackoverflow.com/questions/11354214/creating-dynamically-named-variables-from-user-input) – Marcin May 01 '13 at 17:52

3 Answers3

2

You could simply implement the __getattr__() function for your configuration object like

def __getattr__(self, name):
    if name in self.items:
         return self.items[name]
    else:
         raise AttributeError()

See here for the description for __getattr__() in the python documentation.

MartinStettner
  • 28,719
  • 15
  • 79
  • 106
2

A solution that tries not to reinvent the wheel. Works when you want to only read config once, and its structure is flat.

from collections import namedtuple

def getConfig(config_source):
  # read the config_source into a dict
  # config_source might be a file name or whatnot
  config_dict = read_somehow(config_source)
  tuple_class = namedtuple('Config', config_dict.keys())
  return tuple_class(**config_dict)

The function returns an immutable object with attributes named after config parameter names.

  # suppose config file is something like:
  # a = 1 
  # foo = bar

  cfg = getConfig(...)
  print cfg.a # prints 1
  print cfg.foo # prints foo
  print cfg.unknown # raises AttributeError

I used to use this approach to read sections from standard ConfigParser instances.

9000
  • 39,899
  • 9
  • 66
  • 104
1

I think what you want is just to assign to a member variable, like so:

class Foo(object):
      pass

cfg = Foo()
cfg.item_i_want = "An item"
print cfg.item_i_want

This will print "An item". See: http://ideone.com/LDz7NK

If you want to pick the variable name dynamically, use setattr(cfg, "another_item_i_want", "another item").

Marcin
  • 48,559
  • 18
  • 128
  • 201