title: Python: pass by reference
body: <p>I am trying to understand the behaviour demonstrated below please. Suppose we have the simple class</p>
  
  <pre><code>class A():
      def __init__(self):
          self._df = pd.DataFrame([1,2,3], columns=['c1'], index=['r1', 'r2', 'r3'])
  
      @property
      def df(self):
          return self._df
  
      def summary(self):
          df2 = self.df
          df2['c2'] = pd.Series([4,5,6], index=df2.index)
          return df2
  </code></pre>
  
  <p>and we make an instance <code>a</code>:</p>
  
  <pre><code>a = A()
  </code></pre>
  
  <p>Then <code>a.df</code> returns</p>
  
  <pre><code>    c1
  r1  1
  r2  2
  r3  3
  </code></pre>
  
  <p>Calling the <code>summary</code> method</p>
  
  <pre><code>s = a.summary()
  s
  </code></pre>
  
  <p>returns </p>
  
  <pre><code>    c1  c2
  r1  1   4
  r2  2   5
  r3  3   6
  </code></pre>
  
  <p>which is fine so far. However the <code>df</code> property (and the underlying attribute) of object <code>a</code> have now been changed too.</p>
  
  <pre><code>a.df
  
      c1  c2
  r1  1   4
  r2  2   5
  r3  3   6
  </code></pre>
  
  <p>I understand in broad lines that it has to do with the much-discussed pass by reference design of Python and I suspect the key here is the line <code>df2=self.df</code> in the <code>summary</code> method. Hence <code>df2</code> is actually a reference pointing to the same memory location as <code>self.df</code>. Therefore when we modify the object labeled as <code>df2</code> (by adding one more column in this example) we will be able to see the modified object by calling either <code>df2</code> or <code>self.df</code> because they both point to the same thing. </p>
  
  <p>Is this a fair understanding please? What are the best practices If we wanted to decouple the two? Edit <code>df2</code> without affecting <code>df</code>. Make an explicit copy by <code>df2 = self.df.copy()</code> or something else?</p>