Mutable objects have fields that can be modified; the immutable objects have no fields that can be changed after the object is created. Immutable objects are objects whose state can not change after they have been created. Mutable and Immutable are two categories of objects in java.
Mutable type, in C#, is a type of object whose data members, such as properties, data and fields, can be modified after its creation. Mutable types are used in parallel applications, where the objects of mutable value type are maintained in the stack by the Common Language Runtime (CLR).
Simple put, a mutable object can be changed after it is created, and an immutable object can't. Objects of built-in types like (int, float, bool, str, tuple, unicode) are immutable. Objects of built-in types like (list, set, dict) are mutable. Custom classes are generally mutable.
What? Floats are immutable? But can't I do
x = 5.0
x += 7.0
print x # 12.0
Doesn't that "mut" x?
Well you agree strings are immutable right? But you can do the same thing.
s = 'foo'
s += 'bar'
print s # foobar
The value of the variable changes, but it changes by changing what the variable refers to. A mutable type can change that way, and it can also change "in place".
Here is the difference.
x = something # immutable type
print x
func(x)
print x # prints the same thing
x = something # mutable type
print x
func(x)
print x # might print something different
x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing
x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different
Concrete examples
x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo
x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]
def func(val):
val += 'bar'
x = 'foo'
print x # foo
func(x)
print x # foo
def func(val):
val += [3, 2, 1]
x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
You have to understand that Python represents all its data as objects. Some of these objects like lists and dictionaries are mutable, meaning you can change their content without changing their identity. Other objects like integers, floats, strings and tuples are objects that can not be changed. An easy way to understand that is if you have a look at an objects ID.
Below you see a string that is immutable. You can not change its content. It will raise a TypeError
if you try to change it. Also, if we assign new content, a new object is created instead of the contents being modified.
>>> s = "abc"
>>> id(s)
4702124
>>> s[0]
'a'
>>> s[0] = "o"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>> id(s)
4800100
>>> s += "uvw"
>>> id(s)
4800500
You can do that with a list and it will not change the objects identity
>>> i = [1,2,3]
>>> id(i)
2146718700
>>> i[0]
1
>>> i[0] = 7
>>> id(i)
2146718700
To read more about Python's data model you could have a look at the Python language reference:
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)
First of all, whether a class has methods or what it's class structure is has nothing to do with mutability.
int
s and float
s are immutable. If I do
a = 1
a += 5
It points the name a
at a 1
somewhere in memory on the first line. On the second line, it looks up that 1
, adds 5
, gets 6
, then points a
at that 6
in memory -- it didn't change the 1
to a 6
in any way. The same logic applies to the following examples, using other immutable types:
b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')
For mutable types, I can do thing that actallly change the value where it's stored in memory. With:
d = [1, 2, 3]
I've created a list of the locations of 1
, 2
, and 3
in memory. If I then do
e = d
I just point e
to the same list
d
points at. I can then do:
e += [4, 5]
And the list that both e
and d
points at will be updated to also have the locations of 4
and 5
in memory.
If I go back to an immutable type and do that with a tuple
:
f = (1, 2, 3)
g = f
g += (4, 5)
Then f
still only points to the original tuple
-- you've pointed g
at an entirely new tuple
.
Now, with your example of
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Where you pass
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
(which is a tuple
of tuples
) as val
, you're getting an error because tuple
s don't have a .clear()
method -- you'd have to pass dict(d)
as val
for it to work, in which case you'll get an empty SortedKeyDict
as a result.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With