I\'m confused on what an immutable type is. I know the float
object is considered to be immutable, with this type of example from my book:
class
Mutable object: Object that can be changed after creating it.
Immutable object: Object that cannot be changed after creating it.
In python if you change the value of the immutable object it will create a new object.
Here are the objects in Python that are of mutable type:
list
Dictionary
Set
bytearray
user defined classes
Here are the objects in Python that are of immutable type:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Questions: Is string an immutable type?
Answer: yes it is, but can you explain this:
Proof 1:
a = "Hello"
a +=" World"
print a
Output
"Hello World"
In the above example the string got once created as "Hello" then changed to "Hello World". This implies that the string is of the mutable type. But it is not when we check its identity to see whether it is of a mutable type or not.
a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
print "String is Immutable"
Output
String is Immutable
Proof 2:
a = "Hello World"
a[0] = "M"
Output
TypeError 'str' object does not support item assignment
Questions: Is Tuple an immutable type?
Answer: yes, it is.
Proof 1:
tuple_a = (1,)
tuple_a[0] = (2,)
print a
Output
'tuple' object does not support item assignment
Common immutable type:
int()
, float()
, complex()
str()
, tuple()
, frozenset()
, bytes()
Common mutable type (almost everything else):
list()
, bytearray()
set()
dict()
One trick to quickly test if a type is mutable or not, is to use id()
built-in function.
Examples, using on integer,
>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)
using on list,
>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
A mutable object has to have at least a method able to mutate the object. For example, the list
object has the append
method, which will actually mutate the object:
>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']
but the class float
has no method to mutate a float object. You can do:
>>> b = 5.0
>>> b = b + 0.1
>>> b
5.1
but the =
operand is not a method. It just make a bind between the variable and whatever is to the right of it, nothing else. It never changes or creates objects. It is a declaration of what the variable will point to, since now on.
When you do b = b + 0.1
the =
operand binds the variable to a new float, wich is created with te result of 5 + 0.1
.
When you assign a variable to an existent object, mutable or not, the =
operand binds the variable to that object. And nothing more happens
In either case, the =
just make the bind. It doesn't change or create objects.
When you do a = 1.0
, the =
operand is not wich create the float, but the 1.0
part of the line. Actually when you write 1.0
it is a shorthand for float(1.0)
a constructor call returning a float object. (That is the reason why if you type 1.0
and press enter you get the "echo" 1.0
printed below; that is the return value of the constructor function you called)
Now, if b
is a float and you assign a = b
, both variables are pointing to the same object, but actually the variables can't comunicate betweem themselves, because the object is inmutable, and if you do b += 1
, now b
point to a new object, and a
is still pointing to the oldone and cannot know what b
is pointing to.
but if c
is, let's say, a list
, and you assign a = c
, now a
and c
can "comunicate", because list
is mutable, and if you do c.append('msg')
, then just checking a
you get the message.
(By the way, every object has an unique id number asociated to, wich you can get with id(x)
. So you can check if an object is the same or not checking if its unique id has changed.)
One way of thinking of the difference:
Assignments to immutable objects in python can be thought of as deep copies, whereas assignments to mutable objects are shallow
If you're coming to Python from another language (except one that's a lot like Python, like Ruby), and insist on understanding it in terms of that other language, here's where people usually get confused:
>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!
In Python, assignment is not mutation in Python.
In C++, if you write a = 2
, you're calling a.operator=(2)
, which will mutate the object stored in a
. (And if there was no object stored in a
, that's an error.)
In Python, a = 2
does nothing to whatever was stored in a
; it just means that 2
is now stored in a
instead. (And if there was no object stored in a
, that's fine.)
Ultimately, this is part of an even deeper distinction.
A variable in a language like C++ is a typed location in memory. If a
is an int
, that means it's 4 bytes somewhere that the compiler knows is supposed to be interpreted as an int
. So, when you do a = 2
, it changes what's stored in those 4 bytes of memory from 0, 0, 0, 1
to 0, 0, 0, 2
. If there's another int variable somewhere else, it has its own 4 bytes.
A variable in a language like Python is a name for an object that has a life of its own. There's an object for the number 1
, and another object for the number 2
. And a
isn't 4 bytes of memory that are represented as an int
, it's just a name that points at the 1
object. It doesn't make sense for a = 2
to turn the number 1 into the number 2 (that would give any Python programmer way too much power to change the fundamental workings of the universe); what it does instead is just make a
forget the 1
object and point at the 2
object instead.
So, if assignment isn't a mutation, what is a mutation?
a.append(b)
. (Note that these methods almost always return None
). Immutable types do not have any such methods, mutable types usually do.a.spam = b
or a[0] = b
. Immutable types do not allow assignment to attributes or elements, mutable types usually allow one or the other.a += b
, sometimes not. Mutable types usually mutate the value; immutable types never do, and give you a copy instead (they calculate a + b
, then assign the result to a
).But if assignment isn't mutation, how is assigning to part of the object mutation? That's where it gets tricky. a[0] = b
does not mutate a[0]
(again, unlike C++), but it does mutate a
(unlike C++, except indirectly).
All of this is why it's probably better not to try to put Python's semantics in terms of a language you're used to, and instead learn Python's semantics on their own terms.
A class is immutable if each object of that class has a fixed value upon instantiation that cannot SUBSEQUENTLY be changed
In another word change the entire value of that variable (name)
or leave it alone.
Example:
my_string = "Hello world"
my_string[0] = "h"
print my_string
you expected this to work and print hello world but this will throw the following error:
Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment
The interpreter is saying : i can't change the first character of this string
you will have to change the whole string
in order to make it works:
my_string = "Hello World"
my_string = "hello world"
print my_string #hello world
check this table:
source