21

I need to dynamically create class attributes from a DEFAULTS dictionary.

defaults = {
    'default_value1':True,
    'default_value2':True,
    'default_value3':True,
}

class Settings(object):
    default_value1 = some_complex_init_function(defaults[default_value1], ...)
    default_value2 = some_complex_init_function(defaults[default_value2], ...)
    default_value3 = some_complex_init_function(defaults[default_value3], ...)

I could also achive this by having sth. like __init__ for class creation, in order to dynamically create these attributes from dictionary and save a lot of code and stupid work.

How would you do this?

Thank you very much in advance!

3 Answers 3

32

You could do it without metaclasses using decorators. This way is a bit more clear IMO:

def apply_defaults(cls):
    defaults = {
        'default_value1':True,
        'default_value2':True,
        'default_value3':True,
    }
    for name, value in defaults.items():
        setattr(cls, name, some_complex_init_function(value, ...))
    return cls

@apply_defaults
class Settings(object):
    pass

Prior to Python 2.6 class decorators were unavailable. So you can write:

class Settings(object):
    pass
Settings = apply_defaults(Settings)

in older versions of python.

In the provided example apply_defaults is reusable… Well, except that the defaults are hard-coded in the decorator's body :) If you have just a single case you can even simplify your code to this:

defaults = {
    'default_value1':True,
    'default_value2':True,
    'default_value3':True,
}

class Settings(object):
    """Your implementation goes here as usual"""

for name, value in defaults.items():
    setattr(Settings, name, some_complex_init_function(value, ...))

This is possible since classes (in the sense of types) are objects themselves in Python.

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

2 Comments

You also need to return the "decorated" class (cls in the first example) at the end of the decorator function, don't you? Took me a while to figure out, but unless I do this the class will equal None after definition. Am I missing something, like for example some way of supplying the class by reference instead?
How do i pass defaults to the file like this a = Settings(defaults) settings.py is a particular file
5

I think that's case for metaclass:

class SettingsMeta(type):
    def __new__(cls, name, bases, dct):
        for name, value in defaults.items():
            dct[name] = some_complex_init_function(value, ...)
        return type.__new__(cls, name, bases, dct)

class Settings(object):
    __metaclass__ = SettingsMeta

5 Comments

how do we pass defaults, or how can we initialize any object of this Settings Class
same question with @vijayshanker
The code depends on the defaults dictionary being in scope when defining Settings class.
SettingsMeta and Settings in the setting.py file? How do i pass defaults parameter to it?
With the current code, you cannot pass anything, the defaults dictionary is taken from the scope, defined before Settings class. To be able to pass the defaults, you would need to restructure it. But it feels like a different question to the one asked originally.
2

When defining a class, the local namespace will be converted into the class namespace at the conclusion of the class body. As such, you can accomplish this with:

class Settings(object):
    for key, val in defaults.iteritems():
        locals()[key] = some_complex_init_function(val, ...)

1 Comment

-1 The documentation for locals() says the contents of the dictionary returned should not be modified.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.