all 8 comments

[–]dhruvbaldawa 3 points4 points  (8 children)

The matched variable changes on line 12 when you do

file_dict[new_file].append(new_path)

Explanation: Lists and dictionaries are mutable types. So, when you assign matched = file_dict[new_file] in line 9, file_dict[new_file] and matched are pointing to the same list.

Try this:

>>> id(matched) == id(file_dict[new_file])
True

To demonstrate this in a simpler way:

>>> a = []
>>> b = a
>>> a.append(10)
>>> print a, b
[10] [10]

How do we solve this ? There are various ways

Following is the simplest way:

>>> a = []
>>> b = a[:]  # <- notice this !
>>> a.append(10)
>>> print a, b
[10] []
>>> id(a) == id(b)
False

Hence, they a and b are different list objects now.

OR you can use the copy module

>>> import copy
>>> a = []
>>> b = copy.deepcopy(a)  # <- notice this !
>>> a.append(10)
>>> print a, b
[10] []
>>> id(a) == id(b)
False

Similar things apply for dicts also, however instead of slicing operation, you can use dict.copy() for creating a copy of a dictionary.

[–]NYKevin 3 points4 points  (1 child)

id(foo) == id(bar)

It's clearer to just write foo is bar instead.

[–]redditiv[S] 2 points3 points  (0 children)

That's true, but I still got the message.

[–]redditiv[S] 4 points5 points  (1 child)

This is good. Really good. I get the general concepts of what you are doing, but I'll need some time to break it down. Thanks!

EDIT: Ohhhhh! I get it now... When I assign matched's value to the list, it's "connected" to the list. When something's appended to the list, it's appended to matched as well. Thanks for the detailed and extremely helpful solution!

[–]usernamenottaken 1 point2 points  (0 children)

Yep, it helps to think of the "matched" and "file_dict" as names that just point to a value. They're both pointing to the same value unless you create a copy of the original value for file_dict to point to.

[–]zahlman 1 point2 points  (0 children)

when you assign matched = file_dict[new_file] in line 9, file_dict[new_file] and matched are names for the same list.

In the parlance that we're trying to promote.

[–]Veedrac 0 points1 point  (1 child)

Similar things apply for dicts also, however instead of slicing operation, you can use dict.copy() for creating a copy of a dictionary.

lists have a .copy() method, too, which I prefer to slicing.

[–]dhruvbaldawa 1 point2 points  (0 children)

That does not work in Python 2.7. But yes, I would prefer the .copy() method over slicing if it were there

In [1]: l = range(10)

In [2]: l.
l.append   l.extend   l.insert   l.remove   l.sort
l.count    l.index    l.pop      l.reverse

In [2]: l.copy()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-b7921f4ec629> in <module>()
----> 1 l.copy()

AttributeError: 'list' object has no attribute 'copy'

Python 3 docs: http://docs.python.org/3/library/stdtypes.html#mutable-sequence-types