Mastering Python Strings
A string is a sequence of characters enclosed in quotation marks. In Python, strings are ordered sequences of character data, and thus can be indexed in this way. You can access individual characters of a string using indexing and a range of characters using slicing. Strings are immutable data types, which means that once a string is created, you can't modify it.
In this tutorial, we'll learn everything about Python strings, from how to create and format strings to the different methods you can use to manipulate and work with string data.
Creating Strings
In Python, you can create strings by enclosing a sequence of characters within a pair of single or double quotes. For example:
# Single word
print('hello')
# Entire phrase
print('This is also a string')
# We can also use double quote
print("String built with double quotes")Output:
C:\Users\Your Name> python strings.py
hello
This is also a string
String built with double quotesString Type
In Python, string is an object of type str class. You can verify this with the type() function:
a = "Hello"
print(type(a))Output:
C:\Users\Your Name> python strings.py
<class 'str'>Assign String to a Variable
Assigning a string to a variable is as simple as assigning a value to a variable. For example:
# You can use single or double quotes
a = "Hello"
b = 'Hello'
print(a)
print(b)Output:
C:\Users\Your Name> python strings.py
Hello
HelloMultiline Strings
In Python, you can assign a multiline string to a variable by using three quotes:
a = """Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua."""
# You can also use three single quotes:
b = '''Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.'''
print(a)
print("------")
print(b)Output:
C:\Users\Your Name> python strings.py
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.
------
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua.Strings Arrays
In Python, strings are arrays of bytes representing Unicode characters. A string can be thought of as an array of characters. Like other programming languages, Python strings are indexed starting from 0. For example:
a = "Hello, World!"
print(a[1])Output:
C:\Users\Your Name> python strings.py
eLength of a String
To get the length of a string, use the len() function:
a = "Hello, World!"
print(len(a))Output:
C:\Users\Your Name> python strings.py
13Going through a String with a Loop
Strings are iterable objects, which means you can iterate through each character of the string using a for loop. For example:
for x in "cricket":
print(x)Output:
C:\Users\Your Name> python strings.py
c
r
i
c
k
e
tFinding a String in a String
To check if a certain phrase or character is present in a string, we can use the keyword in.
txt = "Nothing is impossible, you need to believe"
print("impossible" in txt)Output:
C:\Users\Your Name> python strings.py
TrueNot Finding a String in a String
To check if a certain phrase or character is not present in a string, we can use the keyword not in.
txt = "Nothing is impossible, you need to believe"
print("possible" not in txt)Output:
C:\Users\Your Name> python strings.py
TrueImmutable means every method returns a new string
Nothing you call on a string changes it. The original is still there, untouched:
flowchart LR S["s = 'hello'"] --> M["s.upper()"] M --> N["new object 'HELLO'"] S --> U["s is still 'hello'"] S --> A["s[0] = 'H'"] A --> E["TypeError:
'str' object does not
support item assignment"]
s = "hello"
s.upper() # 'HELLO'
print(s) # 'hello' <- unchanged; the result was discarded
s = s.upper() # you must reassign
s[0] = "H" # TypeError: 'str' object does not support item assignmentForgetting to reassign is the single most common string bug — s.strip() on its own
line does nothing at all.
Which is why += in a loop is the wrong tool
Each += builds a whole new string and copies everything so far. Measured, 20,000
characters:
| approach | time | vs += |
|---|---|---|
s += "x" in a loop | 13.73 ms | 1.0× |
"".join(generator) | 5.91 ms | 2.3× faster |
"".join(list) | 1.44 ms | 9.6× faster |
s = ""
for i in range(n):
s += "x" # 13.73 ms — quadratic in disguise
s = "".join("x" for i in range(n)) # 5.91 ms
s = "".join(["x"] * n) # 1.44 msjoin walks the pieces once to total their length, allocates the result a single time,
then copies each piece into place. The list form beats the generator form because
join can measure a list up front but must materialise a generator first.
See it move
len counts code points, not bytes and not what you would call characters. Click
through the samples and watch the three numbers come apart.
Measured:
| string | len | UTF-8 bytes |
|---|---|---|
"cafe" | 4 | 4 |
"café" written with U+00E9 | 4 | 5 |
"café" written as e + combining accent | 5 | 6 |
| one emoji | 1 | 4 |
The two spellings of café print identically and compare unequal, because one is five code points and the other four. Normalise before comparing text that came from outside your program:
import unicodedata
a = "caf\u00e9" # NFC: e-acute as one code point
b = "cafe\u0301" # NFD: e + combining acute
a == b # False
unicodedata.normalize("NFC", b) == a # Truestrip takes a set of characters, not a suffix
This is the string bug most likely to reach production, because the obvious test case passes:
"banana.txt".strip(".txt") # 'banana' <- looks right!
"text.txt".strip(".txt") # 'e' <- everything in ".txt" stripped from BOTH ends
"xxt.txt".strip(".txt") # '' <- the whole string is gone
"text.txt".removesuffix(".txt") # 'text' <- what you actually meantstrip(".txt") removes any of the characters ., t, x repeatedly from both ends.
"banana.txt" survives only because b is not in that set. Use removesuffix (3.9+)
or slice by length.
Indexing raises, slicing does not
s = "python"
s[2:4] # 'th'
s[::-1] # 'nohtyp'
s[99:] # '' <- no error
s[99] # IndexError: string index out of rangeAnd in tests for a substring, not a word: "cat" in "concatenate" is True. Use
.find() when you want a position and can tolerate absence — it returns -1 rather
than raising, unlike .index().
Check yourself
What does 'text.txt'.strip('.txt') return?
strip takes a SET of characters and removes any of '.', 't', 'x' from both ends repeatedly, leaving 'e'. Use removesuffix('.txt') to strip a suffix. 'banana.txt' happens to give the right answer, which is why the bug survives testing.
Show answer
C — 'e' — strip takes a SET of characters and removes any of '.', 't', 'x' from both ends repeatedly, leaving 'e'. Use removesuffix('.txt') to strip a suffix. 'banana.txt' happens to give the right answer, which is why the bug survives testing.
Building a 20,000-character string took 13.73 ms with += in a loop and 1.44 ms with ''.join(list). Why is join faster?
Each += builds a whole new string. join totals the lengths once, allocates the result a single time, and copies each piece in.
Show answer
B — strings are immutable, so each += allocates a new string and copies everything so far — Each += builds a whole new string. join totals the lengths once, allocates the result a single time, and copies each piece in.
Two strings both display as 'café' but compare unequal. What is the most likely reason?
NFC spells it as 4 code points and NFD as 5. They render identically and are different strings. Normalise with unicodedata.normalize('NFC', s) before comparing.
Show answer
B — one uses a single code point for the accented e, the other uses e plus a combining accent — NFC spells it as 4 code points and NFD as 5. They render identically and are different strings. Normalise with unicodedata.normalize('NFC', s) before comparing.
What is the result of s.upper() on its own line, where s = 'hello'?
Every string method returns a new string and leaves the original alone. You must write s = s.upper(). The same trap applies to strip, replace and lower.
Show answer
B — nothing observable: a new string is created and discarded, s is still 'hello' — Every string method returns a new string and leaves the original alone. You must write s = s.upper(). The same trap applies to strip, replace and lower.
Conclusion
In this tutorial, we learned how to create strings, assign strings to variables, and access string characters using indexing and slicing. We also learned how to get the length of a string, iterate through a string using a loop, and check if a string contains a certain phrase or character. For more information on strings, check out the official Python documentation. For more tutorials, Visit Python Central Hub.
Try it: String Exercises
Exercise 1 – Create and Print a String
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 2 – String Length
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.Exercise 3 – String Indexing
Tab indents. Press Escape, then Tab, to leave the editor. Control plus Enter runs the code; Control plus Shift plus Enter submits it.
Press Run to see what your code prints.