Introduction
Python strings are sequences of Unicode characters, which means they can hold letters, numbers, symbols, and characters from almost any language. They’re central to everyday programming: reading files, parsing responses, cleaning data, printing messages, and building user interfaces. A string in Python is immutable, so once created, its characters can’t be changed in place. You create a new string whenever you “modify” one. This design makes code safer and easier to reason about.
A quick peek in the interpreter shows what a string looks like:
s = "Café 🚲"
len(s) # 6 charactersEven with accents and emoji, Python counts characters correctly because it uses Unicode under the hood.
Creating Python Strings
You can create strings with single quotes, double quotes, or triple quotes. All three work the same for simple cases; the choice is mostly about convenience and readability.
a = 'hello'
b = "world"
c = '''A multi-line
string that keeps
line breaks'''
d = str(123) # "123"Use single or double quotes for one‑line text. Use triple quotes when you want embedded newlines or docstrings. Converting non‑string values is as simple as calling str().
A practical example: reading configuration values that may be integers or booleans and storing them as text.
port_text = str(5432) # "5432"
enabled_text = str(True) # "True"Accessing and Manipulating Strings
You often need just a piece of text: the first character, the last three, everything after a prefix. Python gives you indexing and slicing for this.
Indexing
Indexing starts at 0.
s = "python"
s[0] # 'p'
s[5] # 'n'Negative indexing
Negative numbers count from the end.
s[-1] # 'n'
s[-2] # 'o'This is handy for file extensions:
filename = "report.pdf"
ext = filename[-3:] # "pdf"Slicing
Slicing uses start:stop:step. Start is inclusive, stop is exclusive.
s = "ABCDEFGHIJ"
s[2:5] # "CDE"
s[:4] # "ABCD"
s[4:] # "EFGHIJ"
s[::2] # "ACEGI"
s[::-1] # "JIHGFEDCBA" # reversedConsider user input where you want the first 10 characters for a preview:
preview = (user_input[:10] + "...") if len(user_input) > 10 else user_inputImmutability of Strings
Strings can’t be changed in place. Code like s[0] = 'X' raises a TypeError. To “update” a string, build a new one.
s = "python"
# s[0] = 'P' # TypeError
s = "P" + s[1:] # "Python"Immutability prevents accidental side effects when multiple parts of your program share the same text. It’s also why many string operations return new strings instead of altering the original.
A small refactor pattern:
def normalize_username(name: str) -> str:
# build new strings; never mutates in place
return name.strip().lower().replace(" ", "_")String Operations
Common operations include concatenation, repetition, and membership checks. These map to real tasks like building file paths, rendering templates, and quick validations.
Concatenation
first = "Ada"
last = "Lovelace"
full = first + " " + last # "Ada Lovelace"For many pieces, join is cleaner and faster:
parts = ["2025", "10", "31"]
date_text = "-".join(parts) # "2025-10-31"Repetition
banner = "=" * 40
print(banner + "\nSETTINGS\n" + banner)Membership
if "@" in email and "." in email:
domain = email.split("@", 1)[1]Membership checks are also useful for light validation, like ensuring a URL starts with a scheme:
if url.startswith(("http://", "https://")):
...Escape Characters and Quotation Issues
Sometimes you need quotes inside quotes, newlines, or tabs. Escape sequences solve this.
quote = "He said, "Python is fun.""
path = "C:\\Users\\alice\\Documents" # backslashes
multiline = "Line one\nLine two\nLine three"
tabbed = "col1\tcol2\tcol3"A practical case: building CSV-like text in memory.
row = "name,age,city\n"
row += "Ada,36,London\n"Raw strings treat backslashes literally, useful for regex or Windows paths:
pattern = r"\d{3}-\d{2}-\d{4}" # no escaping of backslashes insideString Methods and Built-in Functions
Python ships a deep toolbox for cleaning, searching, and transforming text. Here are the ones you’ll use most:
strip(),lstrip(),rstrip()remove whitespace.lower(),upper(),title(),casefold()change case.replace(old, new, count=-1)swaps substrings.split(sep=None, maxsplit=-1)breaks text into a list.join(iterable)glues pieces together.find(),rfind(),index()locate substrings.startswith(),endswith()match prefixes and suffixes.count(sub)counts occurrences.partition(sep)andrpartition(sep)split once into a 3‑tuple.isalnum(),isalpha(),isdigit(),isspace(),islower(),isupper()for quick checks.encode()andbytes.decode()for conversions between text and bytes.
Examples that mirror everyday chores:
Trim user input and normalize spacing:
raw = " Hello, world! "
clean = " ".join(raw.strip().split()) # "Hello, world!"Extract a domain from a URL with a fallback:
def get_domain(url: str) -> str | None:
url = url.strip()
if "://" in url:
_, _, rest = url.partition("://")
else:
rest = url
host = rest.split("/", 1)[0]
return host or NoneCount words:
text = "one two two three three three"
counts = {}
for word in text.split():
counts[word] = counts.get(word, 0) + 1
# {'one': 1, 'two': 2, 'three': 3}Turn a list into a readable sentence:
items = ["apples", "bananas", "pears"]
if not items:
sentence = ""
elif len(items) == 1:
sentence = items[0]
else:
sentence = ", ".join(items[:-1]) + " and " + items[-1]
# "apples, bananas and pears"Use built-in functions with strings:
len(s)for length.sorted(s)to sort characters.any()/all()across conditions, e.g.,all(c.isdigit() for c in code).ord()andchr()to jump between characters and their code points.
String Formatting
Readable, safe formatting keeps code clear. Python gives you three options: f-strings, str.format(), and the % operator. Use f-strings in new code; they’re concise and fast.
f-strings
name = "Ada"
score = 98.756
print(f"{name} scored {score:.1f}") # Ada scored 98.8You can call expressions directly:
w = 5
h = 3
print(f"Area: {w*h} cm^2")Date formatting with f-strings and format specs:
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
print(f"UTC: {now:%Y-%m-%d %H:%M}")str.format()
template = "User: {user} | Id: {id:08d}"
print(template.format(user="alice", id=321))
# User: alice | Id: 00000321Named fields shine when the same value appears multiple times:
msg = "{who} says hi to {who}"
print(msg.format(who="Bob")) # Bob says hi to BobPercent operator
Older codebases still use %. It’s fine for simple cases, but f-strings are clearer.
print("Pi is about %.2f" % 3.14159) # Pi is about 3.14A realistic formatting task: produce aligned columns for a small report.
rows = [("US", 331_000_000), ("RO", 19_000_000), ("DE", 83_000_000)]
for code, pop in rows:
print(f"{code:>2} | {pop:>12,}")
# US | 331,000,000
# RO | 19,000,000
# DE | 83,000,000Conclusion
Strings are the workhorse of everyday Python. Create them with quotes or str(). Slice them to get what you need. Remember they’re immutable, so build new strings rather than trying to edit characters in place. When you’re composing text, prefer join() over repeated + in loops. Reach for methods like strip, replace, split, and startswith to keep code short and readable. Format values with f-strings and add just enough precision for the job.
Try this: open a Python shell and write a slugify(text) function that lowercases, trims, replaces spaces with hyphens, and strips punctuation. Use only string methods from this guide. Save it, then call it on five different titles. The muscle memory will stick.
