Python class variable getting altered by changing instance variable that should just take its value
<p>I'm stumbling over a weird effect when initializing a Python class. Not sure if I'm overlooking something obvious or not.</p>

<p>First things first, I'm aware that apparently lists passed to classes are passed by reference while integers are passed by value as shown in this example:</p>

<pre><code>class Test:
  def __init__(self,x,y):
    self.X = x
    self.Y = y
    self.X += 1
    self.Y.append(1)

x = 0
y = []
Test(x,y)
Test(x,y)
Test(x,y)
print x, y
</code></pre>

<p>Yielding the result:</p>

<pre><code>0 [1, 1, 1]
</code></pre>

<p>So far so good. Now look at this example:</p>

<pre><code>class DataSheet:
  MISSINGKEYS = {u'Item': ["Missing"]}

  def __init__(self,stuff,dataSheet):
    self.dataSheet = dataSheet
    if self.dataSheet.has_key(u'Item'):
      self.dataSheet[u'Item'].append(stuff[u'Item'])
    else:
      self.dataSheet[u'Item'] = self.MISSINGKEYS[u'Item']
</code></pre>

<p>Calling it like this</p>

<pre><code>stuff = {u'Item':['Test']}
ds = {}
DataSheet(stuff,ds)
print ds
DataSheet(stuff,ds)
print ds
DataSheet(stuff,ds)
print ds
</code></pre>

<p>yields:</p>

<pre><code>{u'Item': ['Missing']}
{u'Item': ['Missing', ['Test']]}
{u'Item': ['Missing', ['Test'], ['Test']]}
</code></pre>

<p>Now lets print <code>MISSINGKEYS</code> instead:</p>

<pre><code>stuff = {u'Item':['Test']}
ds = {}
DataSheet(stuff,ds)
print DataSheet.MISSINGKEYS
DataSheet(stuff,ds)
print DataSheet.MISSINGKEYS
DataSheet(stuff,ds)
print DataSheet.MISSINGKEYS
</code></pre>

<p>This yields:</p>

<pre><code>{u'Item': ['Missing']}
{u'Item': ['Missing', ['Test']]}
{u'Item': ['Missing', ['Test'], ['Test']]}
</code></pre>

<p>The exact same output. Why?</p>

<p><code>MISSINGKEYS</code> is a class variable but at no point is it deliberately altered.</p>

<p>In the first call the class goes into this line:</p>

<pre><code>self.dataSheet[u'Item'] = self.MISSINGKEYS[u'Item']
</code></pre>

<p>Which apparently starts it all. Obviously I only want <code>self.dataSheet[u'Item']</code> to take the value of <code>self.MISSINGKEYS[u'Item']</code>, not to become a reference to it or something like that.</p>

<p>In the following two calls the line</p>

<pre><code>self.dataSheet[u'Item'].append(stuff[u'Item'])
</code></pre>

<p>is called instead and the <code>append</code> works on <code>self.dataSheet[u'Item']</code> AND on <code>self.MISSINGKEYS[u'Item']</code> which it should not.</p>

<p>This leads to the assumption that after the first call both variables now reference the same object.</p>

<p>However although being equal they do not:</p>

<pre><code>ds == DataSheet.MISSINGKEYS
Out[170]: True
ds is DataSheet.MISSINGKEYS
Out[171]: False
</code></pre>

<p>Can someone explain to me what is going on here and how I can avoid it?</p>

<p>EDIT:
I tried this:</p>

<pre><code>ds[u'Item'] is DataSheet.MISSINGKEYS[u'Item'] 
Out[172]: True
</code></pre>

<p>So okay, this one entry in both dictionaries references the same object. How can I just assign the value instead?</p>

<p>Thinking about what happens in Python function calls in terms of "pass by reference" vs "pass by value" is not generally useful; some people like to use the term "pass by object". Remember, everything in Python is an object, so even when you pass an integer to a function (in C terminology) you're actually passing a pointer to that integer object. </p>

<p>In your first code block you do</p>

<pre><code>self.X += 1
</code></pre>

<p>This <em>doesn't</em> modify the current integer object bound to <code>self.X</code>. It creates a new integer object with the appropriate value and binds that object to the <code>self.X</code> name.</p>

<p>Whereas, with </p>

<pre><code>self.Y.append(1)
</code></pre>

<p>you <em>are</em> mutating the current list object that's bound to <code>self.Y</code>, which happens to be the list object that was passed to <code>Test.__init__</code> as its <code>y</code> parameter. This is the same <code>y</code> list object in the calling code, so when you modify <code>self.Y</code> you are changing that <code>y</code> list object in the calling code. OTOH, if you did an assignment like </p>

<pre><code>self.Y = ['new stuff']
</code></pre>

<p>then the name <code>self.Y</code> would be bound to the new list, and the old list (which is still bound to <code>y</code> in the calling code) would be unaffected.</p>

<p>You may find this article helpful: <a href="http://nedbatchelder.com/text/names.html" rel="nofollow">Facts and myths about Python names and values</a>, which was written by SO veteran Ned Batchelder.</p>

python python-2.7 class pass-by-reference