【问题标题】:Global variables in python, undesired behavior.python中的全局变量,不良行为。
【发布时间】:2012-10-12 12:51:54
【问题描述】:

我在这里更新 x,如果我在更新 x 后打印 y,y 将显示反射。但是,在第一个示例中, y 没有显示出这种变化。这就是我迷路的地方。谁能给我解释一下?

x = 2
y = x + 3
###  printing y will yield 5
x = 8    # ok am I updating the same storage space that x pointed to, or is abandoning it and creating
         # another with a value of 8?
###  printing y will still yield 5 (why is that? if Y always points to x and adds 3 to it?)

in contrast with this:

x = [1,2,3]
y = [x,4,5,6]
x[0] = 50
y[2] = 80
z = y[:] + [100,101,1020

【问题讨论】:

  • x[0]=50 视为x.__setitem__(0, 50) 的简写。不要让赋值运算符让你失望。

标签: python variables global-variables


【解决方案1】:

x = 2创建了一个值为2的新对象,x引用它

y = x + 3创建了一个值为5的新对象,y引用它

x = 8 创建了一个值为 8 的新对象,x 现在引用它。值为 2 的对象的引用计数递减,是垃圾回收的候选对象。

x = [1,2,3] 一个新列表(“类型/类列表的对象”)被创建,x 引用它。

y = [x,4,5,6] 一个新的列表对象被创建,y 引用它。之前提到的对象x 基本没有了。这就是所谓的“垃圾”,可能会被所谓的“垃圾收集器”收集起来。

x[0] = 50 将 x 引用的列表的第一个元素更改为 50

y[2] = 80 将 y 引用的列表的第三个元素更改为 80

z = y[:] 创建了一个新的列表对象,其中包含 y 引用的元素的副本。这不会复制第一个元素中的引用 (x)。请参阅copy.deepcopy()

【讨论】:

  • 这是一个非常好的答案,但我认为它没有达到 OP 似乎没有达到的程度。
  • @MarkusUnterwaditzer:好的,我接受它对初学者不友好,但这是我能做的最好的。我想 OP 没有得到的一点是变量名是指对象。 C 程序员经常遇到这个问题,因为他们认为 Python 引用是指向虚拟内存区域的指针。
  • 我的印象是 OP 感到困惑,因为 y 的 int 值被立即处理并且不再依赖于 x。
  • 你去。我对 OP 混淆了什么感到困惑。
  • 我不知道,但在我看来,OP 对x = 2; y = x + 3;x = 8 没有将 y 设置为 11 感到困惑,因为他为是的。
【解决方案2】:

你写道:

打印 y 仍然会产生 5(这是为什么呢?如果 Y 总是指向 x 并在其上加 3?)

您的误解从这里开始。 y 指向 x。 y 的值为 5。听起来您几乎试图将其与单元格可以包含公式的电子表格模型等同起来。编码不是那样的。当你给 y 赋值时,你是在赋值,而不是公式。

【讨论】:

  • 没错。 y 是一个数字,而不是一个函数。该值在分配时计算,然后完成。
【解决方案3】:

当您使用= 运算符并将变量名称作为左侧值时,这会将左侧的名称绑定(或重新绑定)到右侧的对象。 y = x + 3 使y 引用值为5int 对象,然后x = 8 使变量x 引用值为intint 对象。

左边类似于x[0],你正在做项目分配,只改变x中的第0个项目; x这个名字还是指原来的列表,也是y指向的列表的成员。

【讨论】:

    【解决方案4】:

    把它想象成一组盒子。当我们谈论单个变量而不是数组时,X 是一个框的名称,y 也是如此。 所以 x = 2 表示将 2 放入标有 x 的框中。 y = x + 3 表示将 x 中的内容加到 x 上,然后将其放入 y 中。 x = 8 表示将框 x 中的内容替换为 8。 y已经算出来了,不能改。

    对于像 x = [1, 2, 3] 这样的数组,x 不是指一个盒子,而是指一组盒子。 就像 x 指的是框 1、2 和 3,它们中的每一个都恰好具有值 1 2 和 3。 因此,如果我更改列表 x 中第一个框的内容,则 x 本身未更改,它仍然是框列表 - 其中一个框的值已更改。 y 在这种情况下是一个盒子列表,其中第一个并不是真正的盒子,而是包含指向另一组盒子的指针。

    【讨论】:

      【解决方案5】:

      让我们以你的例子,并替换变量:

      原文:

      x = 2
      y = x + 3
      ###  printing y will yield 5
      x = 8    # x now holds the value of 8 instead of 2
      ###  printing y will still yield 5 (why is that? if Y always points to x and adds 3 to it?)
      
      in contrast with this:
      
      x = [1,2,3]
      y = [x,4,5,6]
      x[0] = 50
      

      替换:

      x = 2
      y = 2 + 3
      ###  printing y will yield 5
      x = 8    
      ###  printing y will still yield 5 because it is set to 2+3
      
      
      x = [1,2,3] 
      y = [[1,2,3],4,5,6] #[1,2,3] is the same list as x
      x[0] = 50 # x still holds the value of the same list, 
      #however you're changing the value of the first element of the, 
      #you're not changing x itself though.
      

      在第一个示例中,您正在更改 x 本身的值。在第二个中,您将更改 x 的属性,同时将 x 保留为相同的值。

      【讨论】:

        【解决方案6】:

        如果你真的想要这种行为,你必须使用一个函数:

        >>> x = 2
        >>> y = lambda: x + 3
        >>> y()
        5
        >>> x = 8
        >>> y()
        11
        

        因为 x 是不可变的,所以赋值总是会创建不会反映未来变化的新对象。

        【讨论】:

        • 这不太可能是 OP 想要的。
        【解决方案7】:
        y = x + 3
        

        y 的值会立即计算出来。就是这样。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-07-24
          • 1970-01-01
          • 2015-06-25
          • 2011-07-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多