0

I've written a class in Python for calculations, it looks like:

default = {…}

class Case(object):
    def __init__(self, name, wt, wd, ft, bc, burnup, cr_state):
        self.name = name
        self.burnup = burnup
        self.infn = 'fa-'+faType+'-'+str(self.burnup)+'-'+self.name
        self.data = default
        self.data['caseName'] = name
        self.data['water-temp'] = str(wt)
        self.data['water-den'] = str(wd)
        self.data['fuel-temp'] = str(ft)
        self.data['boron-con'] = str(bc)
        self.cr_state = cr_state
        self.data['cr_state'] = cr_state
        self.data['burnup'] = str(burnup)

Actually it implements more methods, but this should be enough just to illustrate.

The problem is that when I'm trying to create different instances of this class they turn out to have same attributes, like:

basis = Case('basis', 578.0, 0.71614, 578.0, 0.00105, 0, 'empty')
wt450 = Case('wt450', 450.0, 0.71614, 578.0, 0.00105, 0, 'empty')

and after this if I check:

print basis.data == wt450.data

it returns True. Where can the root of the problem be?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
yxfxmx
  • 665
  • 1
  • 6
  • 13
  • 1
    Could you cut this down to a [minimal example](http://stackoverflow.com/help/mcve)? Where is `default` defined? Have you tried `print basis.data, wt450.data` to see what they contain? This is almost certainly a relative of http://stackoverflow.com/q/1132941/3001761 and http://stackoverflow.com/q/1680528/3001761 – jonrsharpe Nov 28 '14 at 13:20
  • default is a dictionary, defined in global scope. If printed, both basis.data and wt450.data contain data, intended to belong to wt450 – yxfxmx Nov 28 '14 at 13:22
  • So you have a single dictionary that both instances share? Then **of course they appear the same**, it's the same dictionary; why did you expect otherwise? Create a *new dictionary*, `self.data = {}` – jonrsharpe Nov 28 '14 at 13:22
  • They both take the global one at first(like self.data = default), and later each instance is meant to update it's own self.data. or does self.data = default just link default to variable, but not fill self.data with data from default? – yxfxmx Nov 28 '14 at 13:24
  • `self.data = default` points the attribute to the single, original dictionary, then you fill it with instance-specific data, overwriting the data of all previous instances. If you want data from `default` as well as local data, assign `self.data = default.copy()` (assuming `default` only holds immutable values). – jonrsharpe Nov 28 '14 at 13:25
  • So, to separate instances I have to copy data from default to each self.data with something like for-in loop in __init__? – yxfxmx Nov 28 '14 at 13:26
  • You can use `self.data = default.copy()` in the simplest case or use `copy.deepcopy` if the default dict is itself comprised of nested data. – Tom Dalton Nov 28 '14 at 13:39

1 Answers1

0

Like the comment from jonrsharpe states, you could copy the content of the default dict with the `dict.copy method.

class Case(object):
    def __init__(self, name, wt, wd, ft, bc, burnup, cr_state):
        self.name = name
        self.burnup = burnup
        self.infn = 'fa-'+faType+'-'+str(self.burnup)+'-'+self.name
        # Copy the content of the dict
        self.data = default.copy()
        # Overwrite data's default values
        self.data['caseName'] = name
        self.data['water-temp'] = str(wt)
        self.data['water-den'] = str(wd)
        self.data['fuel-temp'] = str(ft)
        self.data['boron-con'] = str(bc)
        self.cr_state = cr_state
        self.data['cr_state'] = cr_state
        self.data['burnup'] = str(burnup)

Or, if you want to keep the values synchronized with the default ones, you could create a method that would take the value from the instance and if it can't find the value, then use the one on the default dict. It would look something like this:

class Case(object):
    def __init__(self, name, wt, wd, ft, bc, burnup, cr_state):
        self.name = name
        self.burnup = burnup
        self.infn = 'fa-'+faType+'-'+str(self.burnup)+'-'+self.name
        # We create a NEW dictionary to hold the overwritten values
        self.data = {}
        # Write data to OUR OWN dict
        self.data['caseName'] = name
        self.data['water-temp'] = str(wt)
        self.data['water-den'] = str(wd)
        self.data['fuel-temp'] = str(ft)
        self.data['boron-con'] = str(bc)
        self.cr_state = cr_state
        self.data['cr_state'] = cr_state
        self.data['burnup'] = str(burnup)
    def property(name):
        """
        Return the value of `name`, if name wasn't defined, then use the
        value from default.
        """
        # Return the property from our own dict. If it can't find the property
        # then get it from the default dict. If the property doesn't exists
        # returns None.
        return self.data.get(name, default.get(name))

# Then
print basis.property('caseName') == wt450.property('caseName')
> False
Joaquin Sargiotto
  • 1,646
  • 13
  • 12