[Tutor] assignment to 1 item in dict assigns to all items in dict?

Jeff Shannon jeff@ccvcorp.com
Fri Apr 11 13:19:02 2003


Chris Somerlot wrote:

>>What are you trying to do exactly? The problem seems to stem from the
>>subtle difference between references and copies. 
>>
>
>I see that you're right, I want to create a new instance of line_item
>each time and add it into the dictionary grossinc instead of making a
>reference, but I'm still confused about a good way to do that. Make a
>class? 
>

You could do this with a class, and that would probably be my preferred 
way, especially if there's any common tasks that need to be done on 
line_items -- those can easily become methods of the class.

You can also continue using nested lists and dictionaries, just be sure 
to create new ones for each line_item instead of just referring to the 
same one.  This can be done by using copy.deepcopy(), as Sean suggested, 
or you could write a quick "factory function" that creates a new, 
independent line_item each time it's called.

def new_line_item():
    return [ {'Date': ()}, [], 0 ]

grossinc['salary'] = new_line_item()
grossinc['interest'] = new_line_item()
grossinc['dividends'] = new_line_item()
grossinc['other'] = new_line_item()

However, I do think that a class will allow you more flexibility later 
on, not to mention ease of use.

class line_item:
    def __init__(self, trans = None, assoc = None, goal = 0):
        if  not trans:
            trans = {'Date': ()}
        if not assoc:
            assoc = []
        self.transactions = trans
        self.associations = assoc
        self.goal = goal

grossinc['salary'] = line_item()
grossinc['interest'] = line_item()
grossinc['dividends'] = line_item()
grossinc['other'] = line_item(goal = 575)

grossinc['salary'].goal = 3333

Note that this makes it easier to refer to parts of each line item, 
since you can use a named attribute instead of the cryptic [2], and it 
also allows for more flexibility in creating items that are already 
initalized.  

By the way, you may wonder why I have default values of "None" for the 
dict and list attributes, and then create the appropriate object later. 
 This is because default parameters are only evaluated once, so if I had 
a dict or list as a default parameter, you'd end up with every line_item 
having references to the *same* dict and list -- a close parallel to 
your original problem.  By passing in None as the default, and then 
creating new objects as needed, I ensure that every line_item gets its 
own transaction dict and associations list.  (I don't bother with this 
for the goal, because integers are not mutable, therefore it doesn't 
really matter if all line_items share the same 0 or not.)  See 
http://www.python.org/doc/FAQ.html#6.25 for a bit more information about 
this.

Jeff Shannon
Technician/Programmer
Credit International