Digression on Immutability of Strings
In Chapter 12, Strings
and Chapter 13, Tuples
we noted that strings
and tuples are both immutable. They cannot be
changed once they are created. Programmers experienced in other
languages sometimes find this to be an odd restriction.
Two common questions that arise are how to expand a
string and how to remove characters from a
string.
Generally, we don't expand or contract a
string, we create a new
string that is the concatenation of the original
strings. For example:
>>>
a="abc"
>>>
a=a+"def"
>>>
a
'abcdef'
In effect, Python gives us strings of
arbitrary size. It does this by dynamically creating new
strings instead of modifying existing
strings.
Some programmers who have extensive experience in other languages
will ask if creating a new string from the
original strings is the most efficient way to
accomplish this. Or they suggest that it would be "simpler"
to allow mutable strings for this kind of
concatenation. The short answer is that Python's storage management
makes this use if immutable strings the simplest
and most efficient. We'll discuss this in some depth in the section called "Digression on Immutability of Strings".
Responses to the immutability of tuples and
lists vary, including some of the following
frequently asked questions.
- Q: Since
lists do everything
tuples do and are mutable, why bother with
tuples?
- Q: Wouldn't it be more
efficient to allow mutable
strings?
|
Q:
|
Since
lists do everything
tuples do and are mutable, why bother with
tuples?
|
|
A:
|
Immutable tuples are more efficient
than variable-length lists. There are fewer
operations to support. Once the tuple is
created, it can only be examined. When it is no longer referenced,
the normal Python garbage collection will release the storage for
the tuple.
Many applications rely on fixed-length
tuples. A program that works with
coordinate geometry in two dimensions may use 2-tuples to
represent (
x
,
y
)
coordinate pairs. Another example might be a program that works
with colors as 3-tuples,
(
r
,
g
,
b
),
of red, green and blue levels. A variable-length
list is not appropriate for these kinds of
fixed-length tuple.
|
|
Q:
|
Wouldn't it be "more
efficient" to allow mutable
strings?
|
|
A:
|
There are a number of axes for efficiency: the two most
common are time and memory use.
A mutable string could use less
memory. However, this is only true in the benign special case
where we are only replacing or shrinking the
string within a fixed-size buffer. If the
string expands beyond the size of the
buffer the program must either crash with an exception, or it must
switch to dynamic memory allocation. Python simply uses dynamic
memory allocation from the start. C programs often have serious
security problems created by attempting to access memory outside
of a string buffer. Python avoids this
problem by using dynamic allocation of immutable
string objects.
Processing a mutable string could use
less time. In the cases of changing a
string in place or removing characters from
a string, a fixed-length buffer would
require somewhat less memory management overhead. Rather than
indict Python for offering immutable
strings, this leads to some productive
thinking about string processing in
general.
In text-intensive applications we may want to avoid creating
separate string objects. Instead, we may
want to create a single string object --
the input buffer -- and work with slices of that buffer. Rather
than create strings, we can create
slice objects that describe starting and
ending offsets within the one-and-only input buffer.
If we then need to manipulate these slices of the input
buffer, we can create new strings only as
needed. In this case, our application program is designed for
efficiency. We use the Python string
objects when we want flexibility and simplicity.
|