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.

3
  • 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. Commented May 1, 2013 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? Commented May 1, 2013 at 17:27
  • possible duplicate of Creating dynamically named variables from user input Commented May 1, 2013 at 17:52

3 Answers 3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

It's spelled __getattr__
Or use the setattr operator.
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.

Comments

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").

1 Comment

This way you cannot set the attributes "dynamically" from your database entries ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.