Python function is changing the value of passed pa

2020-05-06 12:19发布

问题:

Here's an example of where I started

mylist = [["1", "apple"], ["2", "banana"], ["3", "carrot"]]

def testfun(passedvariable):
    for row in passedvariable:
        row.append("Something else")
    return "Other answer"


otheranswer = testfun(mylist)
print mylist

I'd expected mylist not to have changed.

I then tried this to remove that temporary column, but that didn't work:

mylist = [["1", "apple"], ["2", "banana"], ["3", "carrot"]]

def testfun(passedvariable):
    for row in passedvariable:
        row.append("Something else")

    # I'm now finished with the "Something else" column, so remove it
    for row in passedvariable: row = row[:-1]
    return "Other answer"


otheranswer = testfun(mylist)
print mylist

I think tried to use a different reference:

mylist = [["1", "apple"], ["2", "banana"], ["3", "carrot"]]

def testfun(passedvariable):
    copyofdata = passedvariable
    for row in copyofdata:
        row.append("Something else")

    # I'm now finished with the "Something else" column, so remove it
    for row in copyofdata: row = row[:-1]
    return "Other answer"


otheranswer = testfun(mylist)
print mylist

I've written little Python scripts for a few months now, but never come across this before. What do I need to learn about, and how do I pass a list to a function and temporarily manipulate it (but leave the original untouched?).

回答1:

Python passes everything by sharing (references passed as value, see call by sharing), however the integrated numeric and string types are immutable, so if you change them the value of the reference is changed instead of the object itself. For mutable types like list, make a copy (e.g. list(passedvariable)). If you are modifying mutable objects within a list (which can only contain references!) you will need to perform a deep copy, to do so use

import copy
copy.deepcopy(passedvariable)

See https://docs.python.org/2/library/copy.html (available since Python 2.6)

Note that since references themselves are passed by value, you cannot change a reference passed as a parameter to point to something else outside of the function (i. e. passedvariable = passedvariable[1:] would not change the value seen outside the function). A common trick is to pass a list with one element and changing that element.



回答2:

mylist outside the function and passedvariable are the same list object. So changing the list is reflected everywhere. The same holds true for copyofdata in the third example. It is no copy, but the same list object again. To make a copy, you have to explicitly copy the list, in your case you even have to copy each element of the list, as they are also list-objects. Now for the second example row = row[:-1]: Here you make a copy of the list, except the last element. So the former row is not changed, but a new list object is bound the the same name row.