python如何在赋值运算符后赋值

How does python assign values after assignment operator

本问题已经有最佳答案,请猛点这里访问。

好吧,一个非常愚蠢的问题,我肯定。但python如何为变量赋值呢?

假设有一个变量a,并分配值a=2。所以python为变量分配一个内存位置,a现在指向包含值2的内存位置。现在,如果我指定一个变量b=a,那么该变量b也指向与该变量a相同的位置。

现在。如果我分配一个变量c=2,它仍然指向与a相同的内存位置,而不是指向新的内存位置。那么,Python是如何工作的呢?它是否首先检查所有先前分配的变量,以检查它们是否共享相同的值,然后将内存位置分配给它?

而且,它与列表的工作方式不同。如果我分配a=[2,3],然后再分配b=[2,3]并使用id功能检查它们的内存位置,我会得到两个不同的内存位置。但是c=b给了我相同的位置。有人能解释一下正确的工作方式和原因吗?

编辑:

基本上,我的问题是因为我刚刚开始学习is操作符,很明显,它只在True指向相同的位置时才使用。因此,如果a=1000b=1000a is bFalsea="world"b="world"是正确的。


我以前就遇到过这个问题,我知道它会让人困惑。这里有两个概念:

  • 有些数据结构是可变的,而另一些则不是
  • python不使用指针…大部分时间
  • 所以让我们来考虑一个列表的例子(你在使用ints时意外地遇到了实习生和窥视孔优化——稍后我会讨论这个问题)

    那么让我们创建两个相同的列表(记住列表是可变的)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    In [42]: a = [1,2]

    In [43]: b = [1,2]

    In [44]: id(a) == id(b)
    Out[44]: False

    In [45]: a is b
    Out[45]: False

    请看,尽管列表是相同的,但是ab是不同的内存位置。现在,这是因为python计算[1,2],将其分配给内存位置,然后调用该位置a(或b)。python要花很长时间检查每个分配的内存位置,以确定[1,2]是否已经存在,并将b分配给与a相同的内存位置。更不用说列表是可变的,也就是说,您可以执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    In [46]: a = [1,2]

    In [47]: id(a)
    Out[47]: 4421968008

    In [48]: a.append(3)

    In [49]: a
    Out[49]: [1, 2, 3]

    In [50]: id(a)
    Out[50]: 4421968008

    看到了吗?a持有的值已更改,但内存位置没有更改。现在,如果一组其他变量名被分配到相同的内存位置,会怎么样?!它们也会被改变,这是语言的一个缺陷。为了解决这个问题,python必须将整个列表复制到一个新的内存位置,因为我想更改EDOCX1的值(0)。

    即使是空列表也是如此:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    In [51]: a = []

    In [52]: b = []

    In [53]: a is b
    Out[53]: False

    In [54]: id(a) == id(b)
    Out[54]: False

    现在,让我们谈谈我所说的关于指针的东西:

    假设您希望两个变量实际讨论相同的内存位置。然后,可以将第二个变量赋给第一个变量:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    In [55]: a = [1,2,3,4]

    In [56]: b = a

    In [57]: id(a) == id(b)
    Out[57]: True

    In [58]: a is b
    Out[58]: True

    In [59]: a[0]
    Out[59]: 1

    In [60]: b[0]
    Out[60]: 1

    In [61]: a
    Out[61]: [1, 2, 3, 4]

    In [62]: b
    Out[62]: [1, 2, 3, 4]

    In [63]: a.append(5)

    In [64]: a
    Out[64]: [1, 2, 3, 4, 5]

    In [65]: b
    Out[65]: [1, 2, 3, 4, 5]

    In [66]: a is b
    Out[66]: True

    In [67]: id(a) == id(b)
    Out[67]: True

    In [68]: b.append(6)

    In [69]: a
    Out[69]: [1, 2, 3, 4, 5, 6]

    In [70]: b
    Out[70]: [1, 2, 3, 4, 5, 6]

    In [71]: a is b
    Out[71]: True

    In [72]: id(a) == id(b)
    Out[72]: True

    看那里发生了什么!ab都被分配到相同的内存位置。因此,您对其中一项所做的任何更改都将反映在另一项上。

    最后,让我们简单地谈谈我前面提到的窥视孔的东西。python试图节省空间。所以,它在启动时将一些小东西加载到内存中(例如,小整数)。因此,当您将一个变量赋给一个小整数(如5)时,python不必在将值赋给内存位置之前计算5,也不必给它赋一个变量名(与您的列表不同)。因为它已经知道5是什么,并且把它存放在某个内存位置,所以它所做的就是为该内存位置分配一个变量名。但是,对于更大的整数,情况不再是这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    In [73]: a = 5

    In [74]: b = 5

    In [75]: id(a) == id(b)
    Out[75]: True

    In [76]: a is b
    Out[76]: True

    In [77]: a = 1000000000

    In [78]: b = 1000000000

    In [79]: id(a) == id(b)
    Out[79]: False

    In [80]: a is b
    Out[80]: False


    您的理解通常是正确的,但值得注意的是,Python列表与C或C++中的数组相比是完全不同的。从文档中:

    ID(OBJ)返回对象的"标识"。这是一个整数(或长整数),它保证在该对象的生存期内是唯一的和常量。生命周期不重叠的两个对象可能具有相同的id()值。

    对您的问题的简单答案是,python中的列表实际上是引用。这会导致它们的内存地址不同,因为地址是引用的地址,而不是我们所期望的对象的地址。


    这是Python为小整数执行的优化。一般来说,不能指望a和c指向同一个位置。如果你用逐渐变大的整数做这个实验,你会发现它在某一点上停止工作。我很确定1000足够大,但我不在计算机附近;我想我记得它是-128到127之间的所有整数都是这样处理的(或者其他一些"整数")。