views:

68

answers:

4

Hi,

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!

+1  A: 

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
Łukasz
A: 

Thank you, that's exactly what I was searching for. Would you say this is a good way of implementing this:

class Settings(object):

    class Meta(type):
        def __new__(cls, name, bases, dct):
            ...
            return type.__new__(cls, name, bases, dct)

    __metaclass__ = Meta

So I have a better code structure...

ahojnnes
update your question or reply to answer, do not use answer for discussion
Anurag Uniyal
+3  A: 

You could do it without metaclasses using decorators. This is a bit more clear way 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, ...))

@apply_defaults
class Settings(object):
    pass

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

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

in older versions of python.

In provided example apply_defaults is reusable… Well, except that defaults are hard-coded in decorator's body :) If you have just 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 sense of types) are objects themselves in Python.

nailxx
A: 

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, ...)
Brian