2

In Python, I want to create a new object by loading a number of variables into it. The easiest way is to pass a dictionary, but that makes programming very annoying: instead of self.health I have to call self.params['health'] all the time. Is there any way to set variable names (fields) dynamically?

I have:

DEFAULT_PARAMS = {
    'health': 10,
    'position': []
}

def __init__(self, params = DEFAULT_PARAMS):
    self.params = params
    print self.params['health']

I want to have:

DEFAULT_PARAMS = {
    'health': 10,
    'position': []
}

class Name():
    def load(self, params):
        # what goes here?

    def __init__(self, params = DEFAULT_PARAMS):
        self.load(params)
        print self.health
krn
  • 6,715
  • 14
  • 59
  • 82

4 Answers4

5
class Name(object):
    def __init__(self, *params):
        self.__dict__.update(DEFAULT_PARAMS)
        self.__dict__.update(params)

b = Name(position=[1,2])
print b.position
Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
  • @khachik: I misunderstood the question originally, so I've revised it considerably. Mind you, I'm not sure what you mean by composite-name keys. – Marcelo Cantos Dec 03 '10 at 12:36
  • Did you actually mean `**params` instead of `*params`? The way it is, it will only work if all parameters passed to `__init__()` are `(key, value)` pairs, which seems strange. – Sven Marnach Dec 03 '10 at 12:41
  • I think he means key values that are invalid attribute names. It's not asked for in the question though, and you have to assume that if we are, for whatever reason using object attribute gimmicks like this, the programmer will be able to avoid these in the dict keys... Or add a pep8 Regex. – David Miller Dec 03 '10 at 12:43
2

You can use

setattr(self, name, value)

to create a new attritbute of self with the dynamic name name and the value value. In your example, you could write

def load(self, params):
    for name, value in params.iteritems():
        setattr(self, name, value)
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
2

If you use the **kwargs syntax then this makes your construction even more flexible when creating the object:

class MyHealthClass(object):
    def __init__(self, *args, **kwargs):
        for key in kwargs:
            setattr(self, key, kwargs[key])
        if not hasattr(self, 'health'):
            raise TypeError('Needs a health')
        print self.health

You can then call this with your dictionary like this:

>>> myvar = MyHealthClass(**DEFAULT_PARAMS)
10

Or using keyword args:

>>> myvar = MyHealthClass(healh=10, wealth="Better all the time")
10
>>> print myvar.health
10
>>> print myvar.wealth
Better all the time
David Miller
  • 2,189
  • 2
  • 15
  • 17
0

You can make attributes for the instance from items coming in the dictionary:

def __init__(self, params=DEFAULT_PARAMS):
  ...
  for k,v in DEFAULT_PARAMS.iteritems():
    setattr(self, escape_attr_name(k), v)
  ...

In escapse_attr_name you take care of characters which aren't allowed in attribute names, but are present in the keys.

khachik
  • 28,112
  • 9
  • 59
  • 94