127

我的理解是 Python 字符串是不可变的。

我尝试了以下代码:

a = "Dog"
b = "eats"
c = "treats"

print a, b, c
# Dog eats treats

print a + " " + b + " " + c
# Dog eats treats

print a
# Dog

a = a + " " + b + " " + c
print a
# Dog eats treats
# !!!

Python不应该阻止分配吗?我可能错过了一些东西。

任何想法?

4

22 回答 22

209

首先a指向字符串“Dog”。然后您将变量更改a为指向一个新字符串“Dog eats Treats”。您实际上并没有改变字符串“Dog”。字符串是不可变的,变量可以指向任何他们想要的。

于 2012-02-01T15:00:03.447 回答
66

字符串对象本身是不可变的。

a指向字符串的变量是可变的。

考虑:

a = "Foo"
# a now points to "Foo"
b = a
# b points to the same "Foo" that a points to
a = a + a
# a points to the new string "FooFoo", but b still points to the old "Foo"

print a
print b
# Outputs:

# FooFoo
# Foo

# Observe that b hasn't changed, even though a has.
于 2012-02-01T14:59:14.960 回答
52

变量 a 指向对象“Dog”。最好将 Python 中的变量视为标签。您可以将标签移动到不同的对象,这就是您更改a = "dog"为时所做的a = "dog eats treats"

然而,不变性是指对象,而不是标签。


如果你试图a[1] = 'z'make "dog"into "dzg",你会得到错误:

TypeError: 'str' object does not support item assignment" 

因为字符串不支持项目分配,因此它们是不可变的。

于 2012-02-01T15:09:06.183 回答
29

只有当我们能够更改内存位置中保存的值而不更改内存位置本身时,某些东西才是可变的。

诀窍是:如果发现更改前后的内存位置相同,则它是可变的。

例如,列表是可变的。如何?

>> a = ['hello']
>> id(a)
139767295067632

# Now let's modify
#1
>> a[0] = "hello new"
>> a
['hello new']
Now that we have changed "a", let's see the location of a
>> id(a)
139767295067632
so it is the same as before. So we mutated a. So list is mutable.

字符串是不可变的。我们如何证明?

> a = "hello"
> a[0]
'h'
# Now let's modify it
> a[0] = 'n'
----------------------------------------------------------------------

我们得到

TypeError:“str”对象不支持项目分配

所以我们未能改变字符串。这意味着字符串是不可变的。

在重新分配时,您将变量更改为指向新位置本身。在这里,您没有改变字符串,而是改变了变量本身。以下是您正在做的事情。

>> a = "hello"
>> id(a)
139767308749440
>> a ="world"
>> id(a)
139767293625808

id重新分配之前和之后是不同的,因此这证明您实际上并没有发生变异,而是将变量指向新位置。这不是改变那个字符串,而是改变那个变量。

于 2015-06-27T05:44:14.230 回答
12

变量只是指向对象的标签。该对象是不可变的,但如果您愿意,可以使标签指向一个完全不同的对象。

于 2012-02-01T14:59:17.143 回答
10

考虑:

>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='qwer'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x109198490>

请注意,当我在变量中存储相同的值两次时,十六进制内存位置没有改变。当我存储不同的值时,它确实发生了变化。字符串是不可变的。不是因为狂热,而是因为您付出了在内存中创建新对象的性能损失。该变量a只是一个指向该内存地址的标签。它可以更改为指向任何东西。

于 2016-11-20T08:31:53.557 回答
7

该语句a = a + " " + b + " " + c可以根据指针进行分解。

a + " "说给我什么a点,不能改变,并添加" "到我当前的工作集中。

记忆:

working_set = "Dog "
a = "Dog" 
b = "eats"
c = "treats"

+ b说给我什么b点,不能更改,并将其添加到当前工作集。

记忆:

working_set = "Dog eats"
a = "Dog" 
b = "eats"
c = "treats"

+ " " + c说添加" "到当前集合。然后给我哪些c点,不能更改,并将其添加到当前工作集。记忆:

working_set = "Dog eats treats"
a = "Dog" 
b = "eats"
c = "treats"

最后,a =说设置我的指针指向结果集。

记忆:

a = "Dog eats treats"
b = "eats"
c = "treats"

"Dog"被回收,因为没有更多的指针连接到它的内存块。我们从未修改过驻留的内存部分"Dog",这就是不可变的意思。但是,我们可以更改哪些标签(如果有)指向该内存段。

于 2012-02-01T15:06:17.077 回答
7

数据和与之关联的标签之间存在差异。例如,当你这样做时

a = "dog"

数据"dog"被创建并放在标签下a。标签可以更改,但内存中的内容不会更改。完成后数据"dog"仍将存在于内存中(直到垃圾收集器将其删除)

a = "cat"

现在在你的程序a中 ^points to ^"cat"但字符串"dog"没有改变。

于 2012-02-01T15:01:48.963 回答
6
l = [1,2,3]
print id(l)
l.append(4)
print id(l) #object l is the same

a = "dog"
print id(a)
a = "cat"
print id(a) #object a is a new object, previous one is deleted
于 2012-02-01T15:03:41.917 回答
4

Python 字符串是不可变的。但是,a不是字符串:它是一个带有字符串值的变量。您不能改变字符串,但可以将变量的值更改为新字符串。

于 2012-02-01T15:00:40.510 回答
3

Python 字符串对象是不可变的。例子:

>>> a = 'tanim'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281536'
>>> a = 'ahmed'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281600'

在这个例子中,我们可以看到,当我们在 a 中分配不同的值时,它不会修改。创建了一个新对象。
而且不能修改。例子:

  >>> a[0] = 'c'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    **TypeError**: 'str' object does not support item assignment

发生错误。

于 2018-04-06T02:15:44.477 回答
2

'mutable' 意味着我们可以更改字符串的内容,'immutable' 意味着我们不能添加额外的字符串。

点击照片证明

于 2018-07-14T13:54:49.857 回答
2

变量可以指向他们想要的任何地方。如果您执行以下操作,将引发错误:

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE
于 2017-02-17T05:46:01.380 回答
1

考虑将此添加到您的示例中

 a = "Dog"
 b = "eats"
 c = "treats"
 print (a,b,c)
 #Dog eats treats
 d = a + " " + b + " " + c
 print (a)
 #Dog
 print (d)
 #Dog eats treats

我在博客中找到的更准确的解释之一是:

在 Python 中,(几乎)一切都是对象。我们通常在 Python 中称为“变量”的东西更恰当地称为名称。同样,“赋值”实际上是将名称绑定到对象。每个绑定都有一个定义其可见性的范围,通常是名称所在的块。

例如:

some_guy = 'Fred'
# ...
some_guy = 'George'

当我们稍后说 some_guy = 'George' 时,包含 'Fred' 的字符串对象不受影响。我们刚刚更改了名称 some_guy 的绑定。但是,我们没有更改“Fred”或“George”字符串对象。就我们而言,他们可能会无限期地活下去。

博客链接:https ://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/

于 2017-04-23T18:03:06.460 回答
1
a = 'dog'
address = id(a)
print(id(a))

a = a + 'cat'
print(id(a))      #Address changes

import ctypes
ctypes.cast(address, ctypes.py_object).value    #value at old address is intact
于 2020-05-16T13:02:33.237 回答
1

为上述答案添加更多内容。

id变量在重新分配时发生变化。

>>> a = 'initial_string'
>>> id(a)
139982120425648
>>> a = 'new_string'
>>> id(a)
139982120425776

这意味着我们已经改变了变量a以指向一个新的字符串。现在存在两个 string(str)对象:

'initial_string'id= 139982120425648

'new_string'id= 139982120425776

考虑下面的代码:

>>> b = 'intitial_string'
>>> id(b)
139982120425648

现在,b指向和与重新分配之前'initial_string'相同。ida

因此,'intial_string'没有发生突变。

于 2018-03-14T11:52:46.780 回答
1

>>> a = 'dogs'

>>> a.replace('dogs', 'dogs eat treats')

'dogs eat treats'

>>> print a

'dogs'

不变的,不是吗?!

变量变化部分已经讨论过了。

于 2015-12-24T10:49:03.037 回答
0

总结:

a = 3
b = a
a = 3+2
print b
# 5

不是一成不变的:

a = 'OOP'
b = a
a = 'p'+a
print b
# OOP

不可变:

a = [1,2,3]
b = range(len(a))
for i in range(len(a)):
    b[i] = a[i]+1

这是 Python 3 中的一个错误,因为它是不可变的。在 Python 2 中并不是一个错误,因为它显然不是一成不变的。

于 2014-10-16T21:00:22.983 回答
0

内置函数id()以整数形式返回对象的标识。这个整数通常对应于对象在内存中的位置。

\>>a='dog'
\>>print(id(a))

139831803293008

\>>a=a+'cat'
\>>print(id(a))

139831803293120

最初,'a' 存储在 139831803293008 内存位置,因为字符串对象在 python 中是不可变的,如果您尝试修改和重新分配引用将被删除,并将成为指向新内存位置 (139831803293120) 的指针。

于 2019-08-28T10:49:01.650 回答
-1

我们只是连接两个字符串值。我们从不改变 (a) 的值。刚才(a)代表另一个具有“dogdog”值的内存块。因为在后端,一个变量永远不会同时代表两个内存块。连接前 (a) 的值是“dog”。但在那之后(a)代表“dogdog”,因为现在(a)在后端代表中。具有“dogdog”值的块。“狗”是代表。由(b)和“狗”不计为垃圾值,直到(b)代表“狗”。

混淆是我们用相同的变量名表示后端的内存块(包含数据或信息。)。

于 2020-03-09T12:20:13.017 回答
-2

您可以使 numpy 数组不可变并使用第一个元素:

numpyarrayname[0] = "write once"

然后:

numpyarrayname.setflags(write=False)

或者

numpyarrayname.flags.writeable = False
于 2017-07-07T14:32:51.817 回答
-2

这张图给出了答案。请阅读。

在此处输入图像描述

于 2019-02-12T06:17:08.940 回答