Archived

This topic is now archived and is closed to further replies.

Dauntless

Python: Strings are immutable??

Recommended Posts

I''m a bit confused, if Strings are immutable, how come I''m able to do this? >>> name = ''sean'' to >>> name = ''bean'' It would seem as if I changed the value of name and it''s therefore mutable. What I can''t seem to do is this: >>> name = ''sean'' >>> name[0] = ''b'' So I''m not exactly sure what the difference is? It seems as if python doesn''t make strings into arrays, in which I can replace individual parts of the string array. Ooops, just read a little further about the id() function. Hmm, when I do id(name) the first time, it prints out value 134926216, but when I assign name = ''bean'', it prints out a different id value, 134935336 . Assuming id''s are analgous to memory locations, python is creating a new object with the value ''bean'', but with the identifier name still. So is there a way I can still retrieve the value ''sean''? What happened to id 134926216? Is there a way I can reference this to retrieve the value ''sean''?
They that can give up essential liberty to purchase a little temporary safety, deserve neither liberty nor safety. - Benjamin Franklin

Share this post


Link to post
Share on other sites
The best explanation I've heard to date is that a reference can best be visualized as an arrow that points to something or other. 'name' is a reference; it points to a string object which holds the string 'sean'. When you direct 'name' to some other string, then the old string is gone. You can't get it back. (unless some other reference also happens to be pointing at it)

As for strings being immutable, it doesn't really matter much, since you can just take the string apart, and build a brand new one with the pieces.

name = 'sean'
name[0] = 'b' # not allowed, because strings are immutable
name = 'b' + name[1:] # Perfectly fine. name now holds 'bean'


[edited by - the speed bump on May 2, 2003 9:03:03 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Dauntless
I''m a bit confused, if Strings are immutable, how come I''m able to do this?
>>> name = ''sean''

to

>>> name = ''bean''


Strings are immutable. Variables referencing strings are mutable. In your example the same variable point to two completely independent strings. If there are no remaining references to that string, the memory it occupies will be reclaimed(ref counting in CPython, Java style gc in Jython)



"To assert that the earth revolves around the sun is as erroneous as to claim that Jesus was not born of a virgin."
-- Cardinal Bellarmine

Share this post


Link to post
Share on other sites
name = ''Sean''
name = 5

that works, too. That doesn''t mean that is string is a number or anything. It just means that it got rid of the first object and made a new one. That''s the same thing that happens when you assign a new string to a variable holding an old string.

The id() function is for determining whether you have a shallow or deep copy.

If you say:
name = ''sean''
othername = name
then:
id(othername) == id(name)

If you say:
name = ''sean''
othername = ''sean''
then:
id(othername) != id(name)

For example:
name = ''sean''
othername = name
record = (name, 10, 5)
otherrecord = (othername, 10, 5)
name = ''richard''

then:
otherrecord[0] == ''richard''

Share this post


Link to post
Share on other sites
After looking at Flarelocke''s example, I thought I was starting to get it, until I did this:

>>>class roster:
>>> pass

>>> name1 = roster()
>>> name1.first = ''sean''
>>> student = name1.first
>>> name1.first = ''bean''

>>> print student
>>> sean

Ehhh? I thought it should print: bean, since that''s what name1.first is now assigned.

I thought that if a variable is simply a reference that points to an object, then if I take a variable name, and assign it to the class''s data member, even if I change the value of the class''s data member, if I print out the variables value, it should point what it was pointing to?

Instead, the variable is pointing to the old value of the class data member (which in a way, solves my earlier problem, of retrieving what the variable originally pointed to). So how do I do it so that I can declare an alias which always returns the value of whatever object it points to?



They that can give up essential liberty to purchase a little temporary safety, deserve neither liberty nor safety. - Benjamin Franklin

Share this post


Link to post
Share on other sites
Maybe some ASCII art will help

quote:
Original post by Dauntless
>>> name1.first = 'sean'


After this line, name1.first points to the string 'sean'.

+------+
name1.first ----->| sean |
+------+
quote:

>>> student = name1.first


Now both student and name1.first point to the same string. Notice that the assignment doesn't make student refer to name1.first in any way. student is simply assigned (made to point to) the same value as name1.first.

student --------->+------+
name1.first ----->| sean |
+------+
quote:

>>> name1.first = 'bean'

Now name1.first is made to point to the string 'bean', while student still points to 'sean', since there is no way student kan "know" that name1.first have been made to point to a different value.

student --------->+------+
name1.first --+ | sean |
| +------+
|
| +------+
+-->| bean |
+------+


Now hopefully you see why "print student" displays "sean" (if not, just ask again )
quote:

So how do I do it so that I can declare an alias which always returns the value of whatever object it points to?

I don't know how to do that (if it's possible), but a simple "work around" is to save a reference to a particular class instance and later access its members, instead of trying to store references to the instance's members directly e.g:

class Student:
pass

class Roster:
pass

# Create a roster with one student named sean
roster = Roster()
roster.student1 = Student()
roster.student1.name = "sean"

# Save a reference to the whole student object
student = roster.student1

# Give the student a new name
roster.student1.name = "bean"

print student.name # This prints "bean"

(Of course, in reality the name and other properties should probably be set in a constructor, and the Roster would most likely have a list or table with Student objects instead of student1, student2, etc, but I wanted to keep this simple and similar to your example).

If your unclear on why this works while your example did not, try drawing what happens, step by step, like I did above and see if it helps.

EDIT: Unfortunately, if roster.student1 is assigned a new Student object (or some other value), then student will still refer to the old Student object, so this isn't exactly what you asked for. Perhaps someone else can help you with that (if it's possible).

EDIT: Fixed some quote and code tags, etc.

[edited by - Dactylos on May 3, 2003 2:26:59 AM]

Share this post


Link to post
Share on other sites
Assignments don''t change a value. Assigning a literal to a name always creates the name and destroys (actually decrefs) the old object. Assigning a name to a name increfs the object to which they both point and decrefs the assignee''s old object.

The reason for this behavior is pretty simple:

class A:
def f(self):
x = self.x
y = self.y


I do this all the time, as well as making names shorter for complicated math functions.

quote:
So how do I do it so that I can declare an alias which always returns the value of whatever object it points to?

I think there''s a copy module.

Share this post


Link to post
Share on other sites