title: Mysteriously assigned constructor argument in iPython
body: <p>This is my very first question to StackOverflow. If the format of this question is not standard, please feel free to let me know.</p>
  <p>I have been transiting from Matlab to Python after I found out about <strong>iPython</strong>. I use <strong>VSCode</strong> and Jupyter interface along with &quot;# %%&quot; header in order to get the interactive console. So far, I love everything and I feel like full transition is needed for my work.</p>
  <p>I have been having some mysterious issue with initialising class instance.</p>
  <p>Suppose we have two minimal files that recreate the issue:</p>
  <p><strong>main.py</strong></p>
  <pre><code># %%
  %reset -f
  from dummy import Dummy
  dummy = Dummy()
  print('created = %s' % dummy.others)
  dummy.receive('something')
  print('received = %s' % dummy.others)
  </code></pre>
  <p><strong>dummy.py</strong></p>
  <pre><code>class Dummy():
      def __init__(self, others=[]):
          self._others = others
          pass
  
      def receive(self, value):
          self._others.append(value)
  
      @property
      def others(self):
          return self._others
  </code></pre>
  <p>When I run main.py for the first time after restarting the Jupyter kernel, I get</p>
  <pre><code>created = []
  received = ['something']
  </code></pre>
  <p>which is totally expected. But, if I run it again, I get</p>
  <pre><code>created = ['something']
  received = ['something', 'something']
  </code></pre>
  <p>indicating that &quot;dummy&quot; variable is not initialised as it should.</p>
  <p>In order to track down the source, I changed the scripts so that</p>
  <p><strong>main.py (debugging)</strong></p>
  <pre><code># %%
  %reset -f
  
  from dummy import Dummy
  try:
      print(dummy.others)
  except:
      print('dummy not found')
  
  dummy = Dummy()
  print('created = %s' % dummy.others)
  dummy.receive('something')
  print('received = %s' % dummy.others)
  </code></pre>
  <p><strong>dummy.py (debugging)</strong></p>
  <pre><code>class Dummy():
      def __init__(self, others=[]):
          print('input = %s' % others)
          self._others = others
          print('internal = %s' % self._others)
          pass
  
      def receive(self, value):
          self._others.append(value)
  
      @property
      def others(self):
          return self._others
  </code></pre>
  <p>When I run the main script after restarting the kernel, I get</p>
  <pre><code>dummy not found
  input = []
  internal = []
  created = []
  received = ['something']
  </code></pre>
  <p>and the below after another run</p>
  <pre><code>dummy not found
  input = ['something']
  internal = ['something']
  created = ['something']
  received = ['something', 'something']
  </code></pre>
  <p>It is so clear that &quot;dummy&quot; variable is successfully deleted after &quot;%reset -f&quot;, but somehow input argument &quot;others&quot; in Dummy constructor is assigned to the previously assigned, rather than &quot;[]&quot;.</p>
  <p>But why?</p>
  <p>When I change &quot;def receive(self, value)&quot; in dummy.py as follows, I don't have the problem anymore:</p>
  <pre><code>def receive(self, value):
      self._others = self._others + [value]
  </code></pre>
  <p>But again, this change is to with mutability if I understand correctly. It should affect the input argument assignment in the constructor.</p>
  <p>Also, this issue doesn't appear when Dummy class is in the same file (main.py)</p>
  <p>Could you please let me know what I am missing?</p>
  <p><strong>Edit:</strong>
  I now understand that I should be careful with mutable init parameters. But my other fundamental question is why &quot;%reset -f&quot; in iPython did not clear everything. It did delete dummy variable, but the init parameter &quot;others&quot; was mysteriously assigned to the previous. Isn't the magic thingy supposed to delete everything?</p>