'str' object does not support item assignment [duplicate]
Asked Answered
B

10

236

I would like to read some characters from a string s1 and put it into another string s2.

However, assigning to s2[j] gives an error:

s2[j] = s1[i]

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

In C, this works:

int i = j = 0;
while (s1[i] != '\0')
    s2[j++] = s1[i++];

My attempt in Python:

s1 = "Hello World"
s2 = ""
j = 0

for i in range(len(s1)):
    s2[j] = s1[i]
    j = j + 1
Bey answered 17/5, 2012 at 7:18 Comment(3)
Btw, don't name your variables after python builtins. If you use str as a variable here, you will be unable to do string conversions with str(var_that_is_not_a_string) or type comparisions such as type(var_with_unknown_type) == str.Coordination
See #41753446 to fix TypeError: 'str' object does not support item assignment.Kenner
Also relevant: Why do we need tuples in Python (or any immutable data type)?Buna
C
150

In Python, strings are immutable, so you can't change their characters in-place.

You can, however, do the following:

for c in s1:
    s2 += c

The reasons this works is that it's a shortcut for:

for c in s1:
    s2 = s2 + c

The above creates a new string with each iteration, and stores the reference to that new string in s2.

Carve answered 17/5, 2012 at 7:19 Comment(7)
Then if I would to read the characters from the string and copy them some where, then how can I do that?Bey
@RasmiRanjanNayak: It depends on what you need to do with those characters. In my answer I've shown how they can be appended to another string.Carve
I would like to write a program "Hello world" to "World Hello". So my code should search for space (' '). So I was looking for helpBey
@RasmiRanjanNayak: print " ".join(reversed("Hello world".split())).capitalize()Coordination
I wanted to know how that affects memory, for example, if I'm dealing with code which has to do this for millions of times, would the new created strings in each iteration get garbage collected or what.. i'm just hopelessly confused hereWesternize
@ronnieaka In older versions of Python, this would indeed generate huge amounts of of garbage. Modern ones can sometimes optimize (which is one of the advantages of a language that doesn't make guarantees about underlying implementation details), but it's better not to rely on that. See #1317387Inodorous
would 2.7 be called as old version?Westernize
E
199

The other answers are correct, but you can, of course, do something like:

>>> str1 = "mystring"
>>> list1 = list(str1)
>>> list1[5] = 'u'
>>> str1 = ''.join(list1)
>>> print(str1)
mystrung
>>> type(str1)
<type 'str'>

if you really want to.

Eider answered 1/8, 2013 at 23:44 Comment(0)
C
150

In Python, strings are immutable, so you can't change their characters in-place.

You can, however, do the following:

for c in s1:
    s2 += c

The reasons this works is that it's a shortcut for:

for c in s1:
    s2 = s2 + c

The above creates a new string with each iteration, and stores the reference to that new string in s2.

Carve answered 17/5, 2012 at 7:19 Comment(7)
Then if I would to read the characters from the string and copy them some where, then how can I do that?Bey
@RasmiRanjanNayak: It depends on what you need to do with those characters. In my answer I've shown how they can be appended to another string.Carve
I would like to write a program "Hello world" to "World Hello". So my code should search for space (' '). So I was looking for helpBey
@RasmiRanjanNayak: print " ".join(reversed("Hello world".split())).capitalize()Coordination
I wanted to know how that affects memory, for example, if I'm dealing with code which has to do this for millions of times, would the new created strings in each iteration get garbage collected or what.. i'm just hopelessly confused hereWesternize
@ronnieaka In older versions of Python, this would indeed generate huge amounts of of garbage. Modern ones can sometimes optimize (which is one of the advantages of a language that doesn't make guarantees about underlying implementation details), but it's better not to rely on that. See #1317387Inodorous
would 2.7 be called as old version?Westernize
T
28

assigning to s2[j] gives an error

Strings are immutable so what you've done in C won't be possible in Python. Instead, you'll have to create a new string.

I would like to read some characters from a string and put it into other string.

Use a slice:

>>> s1 = 'Hello world!!'
>>> s2 = s1[6:12]
>>> print(s2)
world!
Temptress answered 17/5, 2012 at 7:23 Comment(0)
B
5

Strings in Python are immutable (you cannot change them inplace).

What you are trying to do can be done in many ways:

Copy the string:

foo = 'Hello'
bar = foo

Create a new string by joining all characters of the old string:

new_string = ''.join(c for c in oldstring)

Slice and copy:

new_string = oldstring[:]
Bosanquet answered 17/5, 2012 at 7:24 Comment(1)
bar = foo does not copy a string.Core
U
5

Performant methods

If you are frequently performing index replacements, a more performant and memory-compact method is to convert to a different data structure. Then, convert back to string when you're done.

list:

Easiest and simplest:

s = "TEXT"
s = list(s)
s[1] = "_"
s = "".join(s)

bytearray (ASCII):

This method uses less memory. The memory is also contiguous, though that doesn't really matter much in Python if you're doing single-element random access anyways:

ENC_TYPE = "ascii"
s = "TEXT"
s = bytearray(s, ENC_TYPE)
s[1] = ord("_")
s = s.decode(ENC_TYPE)

bytearray (UTF-32):

More generally, for characters outside the base ASCII set, I recommend using UTF-32 (or sometimes UTF-16), which will ensure alignment for random access:

ENC_TYPE = "utf32"
ENC_WIDTH = 4

def replace(s, i, replacement):
    start = ENC_WIDTH * (i + 1)
    end = ENC_WIDTH * (i + 1 + len(replacement))
    s[start:end] = bytearray(replacement, ENC_TYPE)[ENC_WIDTH:]


s = "TEXT HI ひ RA ら GA が NA な DONE"
s = bytearray(s, ENC_TYPE)
replace(s, 1, "_")
s = s.decode(ENC_TYPE)

Though this method may be more memory-compact than using list, it does require many more operations.

Underwaist answered 18/8, 2021 at 23:58 Comment(0)
X
3

Other answers convert the string to a list or construct a new string character by character. These methods can be costly, especially for large strings. Instead, we can use slicing to get the parts of the string before and after the character that is changed, and combine those with the new character.

Here I modify the example code from Crowman's answer to replace a single character in the string using string slicing instead of conversion to a list.

>>> str1 = "mystring"
>>> pos = 5
>>> new_char = 'u'
>>> str2 = str1[:pos] + new_char + str1[pos+1:]
>>> print(str2)
mystrung
>>> type(str2)
<class 'str'>
Xeroderma answered 16/11, 2021 at 22:28 Comment(0)
C
-1

Another approach if you wanted to swap out a specific character for another character:

def swap(input_string):
   if len(input_string) == 0:
     return input_string
   if input_string[0] == "x":
     return "y" + swap(input_string[1:])
   else:
     return input_string[0] + swap(input_string[1:])
Corporal answered 18/8, 2018 at 6:24 Comment(0)
D
-2

How about this solution:

str="Hello World" (as stated in problem) srr = str+ ""

Duodenitis answered 1/8, 2013 at 22:16 Comment(0)
S
-2

Hi you should try the string split method:

i = "Hello world"
output = i.split()

j = 'is not enough'

print 'The', output[1], j
Semipostal answered 1/1, 2016 at 21:52 Comment(0)
D
-2

The 'str' is an immutable data type. Therefore str type object doesn't support item assignment.

s1 = "Hello World"
s2 = ['']*len(s1)
j = 0
for i in range(len(s1)):
s2[j]=s1[i]
j = j + 1
print(''.join(s2)) # Hello World
Dolce answered 17/1, 2022 at 9:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.