0

One of the answers in "python way" to parse and conditionally replace every element in 2D list has revealed to me that I understand even less than I thought.

Given a list of lists containing strings:

myLists = [['5','cat','23'], 
           ['33','parakeet','scalpel'], 
           ['correct','horse','battery','staple','99']]  

I wish to replace each element with the return of:

def numParser(string):
    try:
        return int(string)
    except ValueError:
        return string

My original code was this, but it does not modify the original array. I assumed because list is a copy, not the actual list (am I wrong?):

for single_list in myLists:
    single_list = map(numParser, rawData)

And one of the answers which modifies the lists in place is:

for single_list in myLists:
    for i, item in enumerate(single_list):
        single_list[i] = numParser(item)

Why does the second solution work but not the first?

Community
  • 1
  • 1
Daniel B.
  • 1,254
  • 1
  • 16
  • 35
  • 3
    Because `list = ...` reassigns the name, it doesn't alter the object previously referenced by it at all. Try `list[:] = ...` (and strongly consider **not naming your own list `list`**). *"because `list` is a copy, not the actual list"* - no, I'm afraid you're completely wrong there! – jonrsharpe Jul 08 '15 at 16:29
  • I was actually just about to change that :D I had edited my code for readability here but hadn't considered the name I changed it to. – Daniel B. Jul 08 '15 at 16:30
  • you need to understand python assignment https://stackoverflow.com/questions/17840192/understanding-python-variables-assignment – xuhdev Jul 08 '15 at 16:32
  • This is also worth a read: http://nedbatchelder.com/text/names.html – jonrsharpe Jul 08 '15 at 16:34
  • @jonrsharpe I'll take a look. I'd ask more but I think any question I have is likely covered in the above links. I apologize for not doing my due diligence in checking for duplicates. – Daniel B. Jul 08 '15 at 16:39
  • Ohhh, I see. single_list is a reference to the original list. By making a new assignment I lose the reference but make no modification to the original. – Daniel B. Jul 08 '15 at 16:41

3 Answers3

2

This statement:

single_list = ...

assigns a value to the local variable named single_list. It does not have any effect on any other data.

The statement:

single_list[i] = ...

modifies the value of the object referenced by the local variable named single_list, specifically it sets the value of a particular element of the list.

dsh
  • 12,037
  • 3
  • 33
  • 51
  • I think my question is more why single_list is a reference to a local variable, but single_list[i] references an element of the original list? – Daniel B. Jul 08 '15 at 16:37
  • 1
    That is the language. `foo` is a variable. `foo[i]` is an expression that calls the object's `__getitem__` method, for reading, or `__setitem__` method for modification. – dsh Jul 08 '15 at 16:42
1
for list in myLists:
    list = map(numParser, rawData)

The loop assigns "list" as a variable which references the list in myLists. when you reassign the "list" variable it now points to a new list, but the list in used to reference in "myLists" is unchanged. (Also, you shouldn't use "list" as a variable name as it is a Python keyword).

In the second example you do overwrite the reference to the list in myLists, so it alters myLists.

user1149589
  • 243
  • 3
  • 11
  • Strictly speaking, `list` *isn't* a [keyword](https://docs.python.org/2/reference/lexical_analysis.html#keywords), but shadowing it is certainly a bad idea. – jonrsharpe Jul 08 '15 at 16:33
  • It's been changed in the question. For reference to anybody reading, it was originally "list" not "single_list" – Daniel B. Jul 08 '15 at 16:35
0

In your first example you are assigning a new list to the name "single_list", in the second example you are modifying the list referenced by single_list.

Glen
  • 315
  • 2
  • 10