Python修改列表超出类范围

时间:2018-11-30 15:52:47

标签: python

我试图在Python中调用在类作用域之外定义的函数,它修改了传递的值,而没有对传递的变量的任何引用,但是以某种方式修改了类作用域中的原始变量。

我已经广泛地使用python编写脚本,但是对Classs并没有真正做很多事情。我看过this帖子,它解释了很多,但并没有真正谈论它。该变量肯定超出范围,它如何发生突变?

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])

2 个答案:

答案 0 :(得分:2)

在Python中,所有内容都是一个对象,并且每个对象都以引用方式传递。因此,基本上,您对传递的对象除重新分配外直接进行的任何更改始终始终实时反映在对象本身上。要注意的关键是对象的 mutability ,即对象是否可变,并通过其初始分配。

例如,strint对象是不可变的。请注意,strint下从来没有任何方法可以直接更改对象:

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

请注意str.upper()方法本身如何不会改变s。为了使s成为“ FOO”,您需要重新分配 s

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

但是,通过重新分配对象(obj = ...)可以更改对象引用,其中id(s)现在将有所不同。因此,如果像这样传递了str

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

func(s)

s将保持不变,因为在重新分配string = ...时,string将不再具有与s相同的对象引用。

但是,对于可变对象,只要您不重新分配,对象本身就会进行更改:

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

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

这是因为对象引用(id(l))在函数内保持不变。


在您的情况下,所有说明都表明,如果您想对对象进行某些操作而不希望对其进行突变,则需要传递对象的副本(该对象将具有不同的{{ 1}}),或在本地范围内创建传递的对象的副本:

id

在这种情况下,# 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 返回[:]中的完整slice作为另一个对象。

有关更多信息,请访问relevant read

答案 1 :(得分:1)

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