-2

我有一个清单:

list1 = [1,2,3]

如果我使用一个函数来获取一些我想在原始列表中替换的数据

new_data = [2,3,4]

为什么不

list1 = new_data

改变原始列表?为什么它会创建一个新的引用?

list1[:] = new_data 

确实有效,但为什么其他表达式不起作用?

4

5 回答 5

6

因为这不是 Python 的工作方式。(什么语言可以这样工作?)

Python 变量名就是这样:名字。分配foo = whatever只是foo为由 命名的对象创建一个新名称whatever。简单赋值永远不会改变现有对象。

于 2013-10-28T04:15:06.770 回答
4

Python 的名称是对象上的标签,而不是内存位置。这与 C++ 非常不同。一个对象可能有很多名称,或者如果它包含在某个其他对象(如列表)中,则根本没有名称。

简单的赋值不会改变对象,它们只会重新绑定名称。以前绑定的对象list1不会更改,但如果该名称是程序中引用它的唯一方式,它可能会被垃圾回收。

像 Pythonista这样的网页代码很好地解释了这一点。如果您想更好地理解 Python 变量,我会检查一下。

于 2013-10-28T04:19:02.803 回答
1

因为这就是 Python 中赋值的工作方式。所有分配都会更改指定名称以引用其他对象,而不是它们已经引用的对象。

于 2013-10-28T04:16:26.370 回答
0

Python 名称只是对内存中某个位置的引用。所以:

list1 = new_data

只是让两个变量都引用内存中的相同位置。

另一方面,list1[:]复制 list1

于 2013-10-28T04:17:16.993 回答
0

对于 C 程序员:C 变量是指针,python 变量是句柄。我认为你真的想做这样的事情,但是在 python 中:

// C code
std::vector<int> myvector;

myfunction(std::vector<int> &testvector) {
     if (somearg) {
         testvector.append(4)
     } else {
         int[] myints = {4,15,16};
         testvector = std::vector<int>(myints)
     }
}

因为 testvector 是一个指向对象的指针,并且您更改了它指向的对象,所以无论您采用哪条路径,父级都会看到您的更改。

在 python 中,这看起来像这样:

list1 = [1,2,3]

def modfunc(mylist):
    if (somearg):
        mylist.append(4)
    else:
        mylist = [1,2,3]

虽然第一个可以工作,但第二个不会。在这种情况下, mylist 不是直接指向内存的指针;它指向对象查找表中的一个条目,然后指向真实对象。在失败的情况下,您将名称 mylist 更改为指向不同的对象,但父对象的名称仍指向原始对象。

在它工作的第一种情况下,您实际上尊重名称和对象列表以获取实际对象并直接操作它。父母和孩子的名字都指向这个对象,所以它可以工作。

所以你会怎么做?好吧,简而言之,您不需要这样做。在 C 中,您经常需要引用,因为它将您限制为单个返回值。当然,您可以使用结构,但在 C 中这样做不是很方便。在 python 中,元组是该语言的自然组成部分。所以假设你想在 C 中做这样的事情:

 int sumdefault(std::vector<int> &avector):
     if len(avector) == 0:
         int[] someints = {1,2,3,4,5}
         avector = std::vector<int>(someints);
     return sum(avector)

因此,您需要 int 返回值来返回总和。你也可能会改变一个向量,所以你需要返回一个引用。此外,返回 avector(例如,成对的)可能很危险,因为您正在本地堆栈上创建一个变量,因此返回对它的引用实际上是无效的,但按值返回可能很昂贵(并且不必要)如果avector很大,yada yada。在 python 中,您只需返回两个值:

def sumdefault(mylist=[]):
    if len(mylist) == 0:
        mylist = [1,2,3,4,5]
    return mylist, sum(mylist)

 alist = [2,3,4,5]
 alist, sumalist = sumdefault(alist)

这是(afaik)处理这种模式的正确pythonic方式。您永远不会浪费时间不必要地复制列表 - Python 总是传递对事物的引用。并且 Python 确实没有像 C 那样的“局部”变量:在子函数中创建的变量具有局部名称,但它位于全局堆中,因此即使我们[1,2,3,4,5]在子函数中构造,该内存当我们返回一个函数时不会消失 - 我们的本地名称将消失,但父函数现在将有一个指向它的名称,并且只要某些名称引用它,它就会一直存在。

于 2013-10-28T15:25:41.500 回答