2

Take this as a an example:

class Lizard(object):
    dict_class_var = {"first": "jon", "last": "do"}
    string_class_var = "monkey"


def test():
    liz1 = Lizard()
    liz1.dict_class_var['first'] = "david"
    liz1.string_class_var = "lion"
    print "dict: {}".format(liz1.dict_class_var)
    print "str: {}".format(liz1.string_class_var)

    liz2 = Lizard()
    print "dict: {}".format(liz2.dict_class_var)
    print "str: {}".format(liz2.string_class_var)

    liz3 = Lizard()
    print "dict: {}".format(liz3.dict_class_var)
    print "str: {}".format(liz3.string_class_var)

The Lizard class has two class-level attributes. In test, I'm initializing 3 variables with Lizard() and I'm expecting that all of them point to same dict_class_var and string_class_var which I have updated with liz1 but this is the output:

dict: {'last': 'do', 'first': 'david'}
str: lion
dict: {'last': 'do', 'first': 'david'}
str: monkey
dict: {'last': 'do', 'first': 'david'}
str: monkey

Why the dict has been updated for all of them but the string has not?

Sam R.
  • 16,027
  • 12
  • 69
  • 122
  • 1
    Because a dictionary is *mutable*. `liz1.string_class_var = "lion"` assigns a new string object to a instance attribute. – Martijn Pieters Dec 27 '14 at 23:24
  • @Martijn: That's not really a duplicate. That is asking why class variables are shared. The OP seems to know that, and wants it; this is about why the data is *not* shared. – BrenBarn Dec 27 '14 at 23:25
  • @BrenBarn: yes it is; it tells you that assigning to the instance means you are not sharing. – Martijn Pieters Dec 27 '14 at 23:26
  • @MartijnPieters: Maybe, but that's not the focus of the question. It seems clear to me that the issue here is that the OP doesn't realize that `instance.obj = blah` sets an instance attribute even if the class attribute already exists. (There's probably a dupe of that too, but I can't find one at the moment.) – BrenBarn Dec 27 '14 at 23:27
  • @BrenBarn: several answers there address instance vs. class attributes, in the context of a mutable class attribute. This is just another variation of a FAQ. – Martijn Pieters Dec 27 '14 at 23:30

1 Answers1

3

You did different things to them. For the dict, you did this:

liz1.dict_class_var['first'] = "david"

This modifies the existing dict.

For the string, you did this:

liz1.string_class_var = "lion"

This does not modify the string, but sets the attribute to a new string. Since you set the attribute on the instance liz1, it sets it on the instance, not the class.

If you want to set the class attribute, you need to do Lizard.string_class_var = "lion".

Note that even if the class already has an attribute of the same name, setting it on the instance creates a new instance attribute that shadows the class attribute. If you want to assign to the class attribute you need to name the class explicitly.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384