Corey Petty
Corey Petty

Reputation: 73

How do I use dictionary key,value pair to set class instance attributes "pythonic"ly?

I have created some Python classes to use as multivariate data structures, which are then used for various tasks. In some instances, I like to populate the classes with various value sets. The default parameter filename "ho2.defaults" would look something like this:

name = 'ho2'
mass_option = 'h1o16'
permutation = 'odd'
parity = 'odd'
j_total = 10
lr = 40
br = 60
jmax = 60
mass_lr = 14578.471659
mass_br = 1781.041591
length_lr = ( 1.0, 11.0, 2.65 )
length_br = ( 0.0, 11.0, 2.46 )
use_spline = True
energy_units = 'au'
pes_zpe = -7.407998138300982E-2
pes_cutoff = 0.293994

Currently, I create a dictionary from reading the desired key,value pairs from file, and now I'd like a "pythonic" way of making those dictionary keys be class instance variable names, i.e.

# Instantiate Molecule Class
molecule = Molecule()

# Create Dictionary of default values
default_dict = read_dict_from_file(filename)

# Set populate class instance variables with dictionary values
for key,value in default_dict:
    molecule.key = value

So the Class's instance variable "molecule.name" could be set with the dictionary key,value pair. I could do this by hand, but I'ms sure there is a better way to loop through it. In actuality, the dictionary could be large, and I'd rather allow the user to choose which values they want to populate, so the dictionary could change. What am I missing here?

Upvotes: 5

Views: 3703

Answers (3)

Kirk Strauser
Kirk Strauser

Reputation: 30937

I'd invert the logic so that the object dynamically answers questions:

class Settings(object):
    ATTRS = {'foo', 'bar'}

    def __init__(self, defaults):
        self.__dict__['data'] = defaults.copy()

    def __getattr__(self, key):
        if key not in self.ATTRS or key not in self.data:
            raise AttributeError("'{}' object has no attribute '{}'".format(
                self.__class__.__name__, key))
        return self.data[key]

    def __setattr__(self, key, value):
        self.data[key] = value


s = Settings({'a': 'b', 'foo': 'foo!', 'spam': 'eggs'})
print s.foo

try:
    print s.spam
except AttributeError:
    pass
else:
    raise AssertionError("That should have failed because 'spam' isn't in Settings.ATTRS")

try:
    print s.bar
except AttributeError:
    pass
else:
    raise AssertionError("That should have failed because 'bar' wasn't passed in")

class Molecule(settings):
    ATTRS = {'name', 'mass_option', ...}

molecule = Molecule(default_dict)

Upvotes: 0

Dunes
Dunes

Reputation: 40703

The simple way is:

vars(molecule).update(default_dict)

This will clobber any pre-existing attributes though. For a more delicate approach try:

for name, value in default_dict.items():
    if not hasattr(molecule, name):
        setattr(molecule, name value)

Upvotes: 4

Josh J
Josh J

Reputation: 6893

You would use setattr: setattr(molecule, key, value)

Upvotes: 6

Related Questions