当我写这段代码时:
polly = "alive"
palin = ["parrot", polly]
print(palin)
polly = "dead"
print(palin)
我以为它会输出这个:
"['parrot', 'alive']"
"['parrot', 'dead']"
然而,事实并非如此。我怎样才能让它输出呢?
Python 变量保存对值的引用。因此,当您定义palin
列表时,您传入的是 引用的值polly
,而不是变量本身。
您应该将值想象为气球,变量是与这些气球相关联的线程。"alive"
是一个气球,polly
只是那个气球的一个线程,并且palin
列表有一个不同的线程绑定到同一个气球。在 python 中,列表只是一系列线程,所有线程都从 0 开始编号。
你接下来要做的是将polly
绳子系到一个新气球"dead"
上,但列表仍然保留着系在"alive"
气球上的旧线。
您可以"alive"
通过按索引重新分配列表以引用每个线程来将该线程替换为列表所持有的;在你的例子中是线程1
:
>>> palin[1] = polly
>>> palin
['parrot', 'dead']
在这里,我只是将palin[1]
线程绑定到同一事物polly
上,无论它可能是什么。
请注意,python 中的任何集合,例如dict
、set
、tuple
等,也只是线程的集合。其中一些可以将它们的线程换成不同的线程,例如列表和字典,这就是使 python 中的某些东西“可变”的原因。
另一方面,字符串是不可变的。一旦你定义了一个类似"dead"
or的字符串"alive"
,它就是一个气球。您可以用线程(变量、列表或其他任何东西)将其绑定,但您不能替换其中的字母。您只能将该线程绑定到一个全新的字符串。
python 中的大多数东西都可以像气球一样工作。整数、字符串、列表、函数、实例、类,都可以绑定到一个变量,或者绑定到一个容器中。
您可能还想阅读Ned Batchelder 关于 Python 名称的论文。
在您的第二个打印语句之前,将您的新值存储到palin
:
palin = ["parrot", polly]
当您将字符串放入列表时,列表会保存该字符串的副本。字符串最初是变量、文字值、函数调用的结果还是其他东西都没有关系;当列表看到它时,它只是一个字符串值。更改以后生成的字符串永远不会影响列表。
如果您想存储一个值的引用,当该值更改时会注意到该值,通常的机制是使用包含“引用”值的列表。将其应用于您的示例,您将得到一个嵌套列表。例子:
polly = ["alive"]
palin = ["parrot", polly]
print(palin)
polly[0] = "dead"
print(palin)
该列表将仅包含值,而不是您想要的对变量的引用。但是,您可以在列表中存储一个 lambda,并让 lambda 查找变量的值。
>>> a = 'a'
>>> list = ['a',lambda: a]
>>> list[1]
<function <lambda> at 0x7feff71dc500>
>>> list[1]()
'a'
>>> a = 'b'
>>> list[1]()
'b'
你不能。分配给一个裸名是 Python 始终只重新绑定名称,您无法自定义或监视此操作。
您可以做的是创建polly
一个可变对象而不是字符串,并改变其值而不是重新绑定名称。一个简单的例子:
>>> polly = ['alive']
>>> items = ['parrot', polly]
>>> items
['parrot', ['alive']]
>>> polly[0] = 'dead'
>>> items
['parrot', ['dead']]
其他答案已经很好地解释了正在发生的事情。
这是激发对象使用的(几个)问题之一。例如,有人可能会这样做:
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