简体   繁体   中英

Python Modify List outside scope of a class

I'm trying to call a function defined outside of class scope in Python, and it modifies the passed value, without any references to the passed variable, but somehow the original variable in class scope gets modified.

I have used python extensively for scriting but haven't really done much with Classes. I looked at this post, which explains a lot but doesn't really talk about it. This variable is surely out of scope, how's it getting mutated?

def doSomethingOutOfScope(arr):
    spv = arr[0]
    arr[0] = 'S'


class Solution:
    def doSomethingInScope(self, passed_arr):
        print(passed_arr)                  # prints [0, 1, 2]
        doSomethingOutOfScope(passed_arr)  # passed_arr shouldn't get modified
        print(passed_arr)                  # prints ['S', 1, 2] - Why ?

s = Solution()
s.doSomethingInScope([0, 1, 2])

In Python, everything is an object and every object is passed in reference . Therefore basically any changes you directly made on the passed object besides reassigning is always reflected on the object itself in real time. The key thing to note is the mutability of the object, ie whether the object is mutable pass its initial assignment.

For example, str and int objects are immutable. Note there are never any methods under str and int that changes the object directly:

s = 'foo'  # str type
s.upper()  # FOO
print(s)
# foo

Note how str.upper() method doesn't change s itself. in order to make s into "FOO", you need to reassign s :

s = s.upper()
print(s)
# FOO

However by reassigning the object ( obj = ... ) it changes the object reference, where id(s) will now be different. So if a str was passed like this:

def func(string):
    string = string.upper()

func(s)

s will remain unchanged because at the point of reassignment string = ... , string will no longer have the same object reference of s .

However, with mutable objects, as long as you don't reassign, the object itself will take the changes:

l = list('abcde')
def func(lst, value):
    lst.append(value)
    # no reassignment

func(l, 'f')
print(l)
# ['a', 'b', 'c', 'd', 'e', 'f']

That is because the object reference ( id(l) ) remains the same within the function.


All that said, in your case, if you wanted to do something with the object but not mutate it, you want to either pass a copy of the object (which will have a different id ), or create a copy of the passed object in the local scope:

# pass a copy of the object:
def func(lst):
    lst.append('x')
    return lst

func(lst[:])

# OR, create a local object
def out_of_scope(lst):
    temp_lst = lst[:]
    temp_lst.append('x')
    return temp_lst

In this particular case, [:] returns a full slice of the list as a different object.

For a bit more information, here's a relevant read .

Python列表实际上是可变的,并通过引用传递

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM