2

I am experiencing an unexpected behavior with this data structure.

    class IncomeVerification(object):

        data = {'IncomeYears': []}

        def __init__(self, income_years):
            for year in income_years:
                new_year = IncomeYear(year).data
                self.data['IncomeYears'].append(new_year)

    class IncomeYear(object):
        data = {'IncomeYear': {'Year': None}}

        def __init__(self, year, reported_income=None):
            self.data['IncomeYear']['Year'] = year

    income_years = ['2014', '2013', '2012', '2011']

    foo = IncomeVerification(income_years)
    print foo.data

This returns,

     {'IncomeYears': [{'IncomeYear': {'Year': '2011'}}, {'IncomeYear': {'Year': '2011'}}, {'IncomeYear': {'Year': '2011'}}, {'IncomeYear': {'Year': '2011'}}]}

I am expecting,

    {'IncomeYears': [{'IncomeYear': {'Year': '2014'}}, {'IncomeYear': {'Year': '2013'}}, {'IncomeYear': {'Year': '2012'}}, {'IncomeYear': {'Year': '2011'}}]}

I believe the nested nature of my dictionaries creates unique key problems and therefore overwrites existing entries. Any ideas on how to modify the call above to get my desired result?

Thank you.

Zihs
  • 347
  • 2
  • 4
  • 17
  • The year values in the returned output are all 2011. In my expected result, they are 2014, 2013, 2012, and 2011 as per the indexes of the income_years array. – Zihs Oct 21 '15 at 19:11

2 Answers2

2

You are repeatedly adding references not a new dict/object with self.data['IncomeYears'].append(new_year) in your own code so any time you make a change you are in fact changing the same object.

You would need to deepcopy data with your own code:

from copy import deepcopy
class IncomeVerification(object):

        data = {'IncomeYears': []}
        def __init__(self, income_years):
            for year in income_years:
                new_year = deepcopy(IncomeYear(year).data)

Which would output:

{'IncomeYears': [{'IncomeYear': {'Year': '2014'}}, {'IncomeYear': {'Year': '2013'}}, {'IncomeYear': {'Year': '2012'}}, {'IncomeYear': {'Year': '2011'}}]}

Or better again make data an instance attribute in IncomeYear as opposed to a class attribute that it currently is which is created once and shared amongst all instances:

class IncomeVerification(object):
        data = {'IncomeYears': []}
        def __init__(self, income_years):
            for year in income_years:
                new_year = IncomeYear(year).data
                self.data['IncomeYears'].append(new_year)

class IncomeYear(object):
    def __init__(self, year, reported_income=None):
        # new dict/object for each instance
        self.data = {'IncomeYear': {'Year': None}}
        self.data['IncomeYear']['Year'] = year

income_years = ['2014', '2013', '2012', '2011']

foo = IncomeVerification(income_years)
print(foo.data)

Which again outputs:

{'IncomeYears': [{'IncomeYear': {'Year': '2014'}}, {'IncomeYear': {'Year': '2013'}}, {'IncomeYear': {'Year': '2012'}}, {'IncomeYear': {'Year': '2011'}}]}

class vs instance attributes

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
2

This happens because the data attribute in your classes are class variables, which behave like static attributes from other programming languages, in that they are unique to the class, and not to each of its instances.

For your code to work, you must make them instance variables by moving them into your __init__() method, like so:

class IncomeVerification(object):

    def __init__(self, income_years):
        self.data = {'IncomeYears': []}
        for year in income_years:
            new_year = IncomeYear(year).data
            self.data['IncomeYears'].append(new_year)

class IncomeYear(object):

    def __init__(self, year, reported_income=None):
        self.data = {'IncomeYear': {'Year': None}}
        self.data['IncomeYear']['Year'] = year

income_years = ['2014', '2013', '2012', '2011']

foo = IncomeVerification(income_years)
print  foo.data

Running this would return:

{'IncomeYears': [{'IncomeYear': {'Year': '2014'}}, {'IncomeYear': {'Year': '2013'}}, {'IncomeYear': {'Year': '2012'}}, {'IncomeYear': {'Year': '2011'}}]}

As you expected.

zayora
  • 418
  • 2
  • 12