Aren't Python strings immutable? Then why does a + " " + b work?
Asked Answered
O

22

137

My understanding was that Python strings are immutable.

I tried the following code:

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
# !!!

Shouldn't Python have prevented the assignment? I am probably missing something.

Any idea?

Omarr answered 1/2, 2012 at 14:56 Comment(7)
The string itself is immutable but the label can change.Allottee
Assigning a new value to an existing variable is perfectly valid. Python does not have constants. This is independent from data type mutability.Meristic
You may want to take a look at the id() function. a will have a different id before and after the assignment, indicating that it is pointing at different objects. Likewise with code like b = a you'll find that a and b will have the same id, indicating they're referencing the same object.Scrutator
See python.net/~goodger/projects/pycon/2007/idiomatic/…Skive
The link from delnan is exactly what I was refering to.Allottee
@delnan well illustrated example.Football
You should rather ask why a = []; a += [1] mutates the list (not just the variable) but a = 'x'; a += 'y' is still valid code. xDBeauchamp
I
226

First a pointed to the string "Dog". Then you changed the variable a to point at a new string "Dog eats treats". You didn't actually mutate the string "Dog". Strings are immutable, variables can point at whatever they want.

Indistinctive answered 1/2, 2012 at 15:0 Comment(2)
It's even more convincing to try something like x = 'abc'; x[1] = 'x' in the Python replHekking
If you'd like to understand the internals a bit more, see my answer. https://mcmap.net/q/166362/-aren-39-t-python-strings-immutable-then-why-does-a-quot-quot-b-workNonnah
M
69

The string objects themselves are immutable.

The variable, a, which points to the string, is mutable.

Consider:

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.
Magritte answered 1/2, 2012 at 14:59 Comment(7)
@Omarr try the same kind of operations with lists (that are mutable) to see the difference a.append(3) corresponds to a = a + "Foo"Mucilage
@Mucilage a.append(3) is not the same as a = a + 3. It's not even a += 3 (inplace addition is equivalent to .extend, not to .append).Skive
@delnan and so, what? For the sake of showing that strings and lists behave differently you can assume that a = a+"Foo" is the same as a.append(something). In any case it's not the same. Obviously. Were you happier reading a.extend([something]) instead of a.append(something)? I don't see that big difference in this context. But probably I'm missing something. Thruth depends on contextMucilage
@jimifiki: What are you talking about? + behaves the same for lists and strings - it concatenates by creates a new copy and not mutating either operand.Skive
@delnan A=[0,1,2];B=A;A.append(3); print A,B ; a = "012"; b = a ; a = a + "3"; print a,b; I guess I misunderstood youMucilage
@Mucilage Yes, there must be a misunderstanding. I took your first comment as "a = a + ... is the same as a.append(...) for lists". Your snippet shows this, and there's more hints you're perfectly aware of that. So I don't understand why you relate (even in your second comment) that they are the same?Skive
The truly important point to take away from all this is that strings don't have an append function because they're immutable.Romina
M
54

The variable a is pointing at the object "Dog". It's best to think of the variable in Python as a tag. You can move the tag to different objects which is what you did when you changed a = "dog" to a = "dog eats treats".

However, immutability refers to the object, not the tag.


If you tried a[1] = 'z' to make "dog" into "dzg", you would get the error:

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

because strings don't support item assignment, thus they are immutable.

Monde answered 1/2, 2012 at 15:9 Comment(0)
W
31

Something is mutable only when we are able to change the values held in the memory location without changing the memory location itself.

The trick is: If you find that the memory location before and after the change are the same, it is mutable.

For example, list is mutable. How?

>> 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 string is immutable. How do we prove it?

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

we get

TypeError: 'str' object does not support item assignment

So we failed mutating the string. It means a string is immutable.

In you reassigning, you change the variable to point to a new location itself. Here you have not mutated the string, but mutating the variable itself. The following is what you are doing.

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

id before and after reassignment is different, so it this proves that you are actually not mutating, but pointing the variable to new location. Which is not mutating that string, but mutating that variable.

Warison answered 27/6, 2015 at 5:44 Comment(0)
N
14

Consider:

>>> 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>

Notice that the hex memory location did not change when I stored the same value in the variable twice. It did change when I stored a different value. The string is immutable. Not because of zealotry, but because you pay the performance penalty of creating a new object in memory. The variable a is just a label pointing to that memory address. It can be altered to point to anything.

Nonnah answered 20/11, 2016 at 8:31 Comment(2)
What happens to the memory address that was used for the initial string (asdf)? is it left alone or it is when "garbage collection" gets triggered?Jesu
@Jesu for most object types, the garbage collector will see that no references remain for that memory location and call free on it. But strings are a bit different in python because of string interning. You can test it by assigning a='asdf' at the end of the example. The memory address will again be 0x1091aab90. You can even import gc and call gc.collect() before doing the assignment, and it will still get that same address since 'asdf' remains interned.Fireplug
K
12

A variable is just a label pointing to an object. The object is immutable, but you can make the label point to a completely different object if you want to.

Koger answered 1/2, 2012 at 14:59 Comment(0)
A
7

There is a difference between data and the label it is associated with. For example when you do

a = "dog"

the data "dog" is created and put under the label a. The label can change but what is in the memory won't. The data "dog" will still exist in memory (until the garbage collector deletes it) after you do

a = "cat"

In your programm a now ^points to^ "cat" but the string "dog" hasn't changed.

Allottee answered 1/2, 2012 at 15:1 Comment(0)
H
7

The statement a = a + " " + b + " " + c can be broken down based upon pointers.

a + " " says give me what a points to, which can't be changed, and add " " to my current working set.

memory:

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

+ b says give me what b points to, which can't be changed, and add it to current working set.

memory:

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

+ " " + c says add " " to the current set. Then give me what c points to, which can't be changed, and add it to current working set. memory:

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

Finally, a = says set my pointer to point to the resulting set.

memory:

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

"Dog" is reclaimed, because no more pointers connect to it's chunk of memory. We never modified the memory section "Dog" resided in, which is what is meant by immutable. However, we can change which labels, if any, point to that section of memory.

Huggins answered 1/2, 2012 at 15:6 Comment(0)
S
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
Slapup answered 1/2, 2012 at 15:3 Comment(0)
R
4

Python strings are immutable. However, a is not a string: it is a variable with a string value. You can't mutate the string, but can change what value of the variable to a new string.

Reel answered 1/2, 2012 at 15:0 Comment(0)
C
4

Python string objects are immutable. Example:

>>> 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'

In this example we can see that when we assign different value in a it doesn't modify.A new object is created.
And it can't be modified. Example:

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

A error occurs.

Curtal answered 6/4, 2018 at 2:15 Comment(0)
R
2

Variables can point to anywhere they want.. An error will be thrown if you do the following:

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE
Remorseless answered 17/2, 2017 at 5:46 Comment(0)
C
2

'mutable' means that we can change the content of the string, 'immutable' means that we can't add an extra string.

click for photo proof

Camarata answered 14/7, 2018 at 13:54 Comment(0)
M
2
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
Merely answered 16/5, 2020 at 13:2 Comment(1)
While this code may resolve the OP's issue, it is best to include an explanation as to how your code addresses the OP's issue. In this way, future visitors can learn from your post, and apply it to their own code. SO is not a coding service, but a resource for knowledge. Also, high quality, complete answers are more likely to be upvoted. These features, along with the requirement that all posts are self-contained, are some of the strengths of SO as a platform, that differentiates it from forums. You can edit to add additional info &/or to supplement your explanations with source documentationJacquetta
O
1

>>> a = 'dogs'

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

'dogs eat treats'

>>> print a

'dogs'

Immutable, isn't it?!

The variable change part has already been discussed.

Orchardist answered 24/12, 2015 at 10:49 Comment(1)
This isn't proving or disproving the mutability of python strings, just that the replace() method returns a new string.Dordrecht
M
1

Consider this addition to your example

 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

One of the more precise explanations I found in a blog is:

In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.

Eg:

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

When we later say some_guy = 'George', the string object containing 'Fred' is unaffected. We've just changed the binding of the name some_guy. We haven't, however, changed either the 'Fred' or 'George' string objects. As far as we're concerned, they may live on indefinitely.

Link to blog: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/

Malagasy answered 23/4, 2017 at 18:3 Comment(0)
O
1

Adding a bit more to above-mentioned answers.

id of a variable changes upon reassignment.

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

Which means that we have mutated the variable a to point to a new string. Now there exist two string(str) objects:

'initial_string' with id = 139982120425648

and

'new_string' with id = 139982120425776

Consider the below code:

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

Now, b points to the 'initial_string' and has the same id as a had before reassignment.

Thus, the 'intial_string' has not been mutated.

Odontalgia answered 14/3, 2018 at 11:52 Comment(0)
C
1

The built-in function id() returns the identity of an object as an integer. This integer usually corresponds to the object’s location in memory.

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

139831803293008

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

139831803293120

Initially, 'a' is stored in 139831803293008 memory location, as the string object is immutable in python if you try to modify and reassign the reference will be removed and will be a pointer to a new memory location(139831803293120).

Counterclaim answered 28/8, 2019 at 10:49 Comment(0)
D
0

Summarizing:

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

Not immutable:

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

Immutable:

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

This is an error in Python 3 because it is immutable. And not an error in Python 2 because clearly it is not immutable.

Disciplinant answered 16/10, 2014 at 21:0 Comment(0)
D
-1

We r just concatenate the two string values. We never change the value of (a). Just now (a) represent another memory block that has "dogdog" value. Because in the backend, one variable never represent two memory blocks at same time. The value of (a) before concatenation was "dog". But after that (a) represent the "dogdog", because now (a) in backend rep. the block that has "dogdog" value. And "dog" is rep. by (b) and "dog" isn't counted as garbage value until (b) represent the "dog".

The confusion is we represent the memory blocks(that contain data or info.) in backend with same variable name.

Devolve answered 9/3, 2020 at 12:20 Comment(0)
C
-2

You can make a numpy array immutable and use the first element:

numpyarrayname[0] = "write once"

then:

numpyarrayname.setflags(write=False)

or

numpyarrayname.flags.writeable = False
Chino answered 7/7, 2017 at 14:32 Comment(0)
R
-2

This image gives the answer. Please read it.

enter image description here

Rigney answered 12/2, 2019 at 6:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.