【问题标题】:Python list doesn't reflect variable changePython 列表不反映变量变化
【发布时间】:2012-08-18 07:33:43
【问题描述】:

当我写这段代码时:

polly = "alive"
palin = ["parrot", polly]
print(palin)
polly = "dead"
print(palin)

我以为它会输出这个:

"['parrot', 'alive']"
"['parrot', 'dead']"

然而,事实并非如此。如何让它输出?

【问题讨论】:

标签: python list variables


【解决方案1】:

Python 变量持有对的引用。因此,当您定义palin 列表时,您传入的是polly 引用的值,而不是变量本身。

您应该将值想象为气球,变量是与这些气球绑定的线程。 "alive" 是一个气球,polly 只是该气球的一个线程,而palin 列表有一个不同 线程绑定到同一个气球。在 python 中,列表就是一系列线程,所有线程都从 0 开始编号。

您接下来要做的是将polly 字符串绑定到新气球"dead",但列表仍保留与"alive" 气球绑定的旧线程。

您可以通过按索引重新分配列表以引用每个线程来将该线程替换为列表所持有的"alive";在您的示例中,这是线程 1:

>>> palin[1] = polly
>>> palin
['parrot', 'dead']

在这里,我只是将 palin[1] 线程绑定到 polly 所绑定的同一事物上,无论它可能是什么。

请注意,python 中的任何集合,例如dictsettuple 等,也只是线程的集合。其中一些可以将它们的线程换成不同的线程,例如列表和字典,这就是使 python 中的某些东西“可变”的原因。

另一方面,字符串是可变的。一旦定义了"dead""alive" 之类的字符串,它就是one 气球。您可以用线程(变量、列表或其他任何东西)将其绑定,但您不能替换其中的字母。您只能将该线程绑定到一个完全 new 字符串。

python 中的大多数东西都可以像气球一样工作。整数、字符串、列表、函数、实例、类,都可以绑定到变量或容器中。

您可能也想阅读Ned Batchelder's treatise on Python names

【讨论】:

  • 谢谢,我现在相信我问的问题不正确,但谢谢
  • 我喜欢气球的比喻——特别是如果它们是氦气球,当最后一根绳子被释放时会飘走......(+1)。
  • 这是否意味着垃圾收集策略对应天气?
  • @DSM:完全正确 :-) GC 是吹走任何未系紧的气球的风。 :-)
  • @user1404053:那么你需要一个可变气球。例如,用户定义的类,而不是字符串。
【解决方案2】:

在您的第二个打印语句之前,将您的新值存储到palin

palin = ["parrot", polly]

【讨论】:

  • 在不恢复新值的情况下怎么做?
  • @user1404053:不是你问的那样。在 Python 中,字符串是不可变的,因此无法更改 polly 中的值,因此无法在其他任何地方更改它。行polly = "dead"rebinding operation rather than a mutating one
【解决方案3】:

当您将字符串放入列表时,列表会保存该字符串的副本。字符串最初是变量、文字值、函数调用的结果还是其他东西都没有关系;当列表看到它时,它只是一个字符串值。更改以后生成的字符串永远不会影响列表。

如果您想存储对某个值的引用,该值会在该值更改时发出通知,通常的机制是使用包含“引用”值的列表。将其应用于您的示例,您将得到一个嵌套列表。示例:

polly = ["alive"]
palin = ["parrot", polly]
print(palin)
polly[0] = "dead"
print(palin)

【讨论】:

    【解决方案4】:

    该列表将仅包含值,而不是您想要的变量引用。但是,您可以在列表中存储一个 lambda,并让 lambda 查找变量的值。

    >>> a = 'a'
    >>> list = ['a',lambda: a]
    >>> list[1]
    <function <lambda> at 0x7feff71dc500>
    >>> list[1]()
    'a'
    >>> a = 'b'
    >>> list[1]()
    'b'
    

    【讨论】:

    • 更多解释:这里的lambda: a基本上是一个函数,它只返回存储在a中的值。这就是为什么你可以使用命令list[1]();这意味着您调用存储在list[1] 中的函数。 (另外,适当的 gravatar,@Jonatan)
    • 非常正确,感谢您的解释。我也完全忘记了我的头像,哈哈!
    【解决方案5】:

    你不能。给一个裸名赋值是 Python 总是只重新绑定这个名字,你不能自定义或监控这个操作。

    您可以做的是使polly 成为可变对象而不是字符串,并改变其值而不是重新绑定名称。一个简单的例子:

    >>> polly = ['alive']
    >>> items = ['parrot', polly]
    >>> items
    ['parrot', ['alive']]
    >>> polly[0] = 'dead'
    >>> items
    ['parrot', ['dead']]
    

    【讨论】:

      【解决方案6】:

      其他答案已经很好地解释了正在发生的事情。

      这是促使使用对象的(几个)问题之一。例如,可以这样做:

      class Animal:
          def __init__(self, aniType, name):
              self.aniType = aniType
              self.name = name
              self.isAlive = True
      
          def kill(self):
              self.isAlive = False
      
          def getName(self):
              return self.name
      
          def getType(self):
              return self.aniType
      
          def isLiving(self):
              return self.isAlive
      
      
      polly = Animal("parrot", "polly")
      
      print(polly.getName()+' the '+polly.getType()+' is alive?')
      print(polly.isLiving())
      
      polly.kill()
      
      print(polly.getName()+' the '+polly.getType()+' is alive?')
      print(polly.isLiving())
      

      对于一项简单的任务,乍一看可能需要大量代码,但对象通常是处理此类事情的最佳方式,因为它们有助于保持一切井井有条。

      这是该程序的输出:

      polly the parrot is alive?
      True
      polly the parrot is alive?
      False
      

      【讨论】:

        猜你喜欢
        • 2021-05-21
        • 2020-12-13
        • 1970-01-01
        • 1970-01-01
        • 2014-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-23
        相关资源
        最近更新 更多