Python strings look simple, but their quotes, prefixes, and formatting rules can be confusing at first. A useful way to understand them is to ask three questions:
- Which quotes define the string?
- What do prefixes such as
f,r,b, andumean? - How do you insert and format values inside a string?
This guide answers each question and explains the edge cases worth knowing.
1. Single and Double Quotes
Single and double quotes both create values of type str. They behave exactly the same:
name1 = 'Bob'name2 = "Bob"
print(name1 == name2) # TrueChoose the style that makes the text easiest to read and requires the fewest escapes:
text1 = "I'm Bob"text2 = 'She said, "Hello."'If the content contains the same quote used to define the string, escape it with a backslash:
text = 'I\'m Bob'print(text) # I'm BobMost projects adopt one quote style for consistency and switch only when it improves readability.
2. Triple Quotes and Multiline Strings
Three single quotes (''') or three double quotes (""") create a string that can span several lines:
text = """First lineSecond lineThird line"""
print(text)Triple-quoted strings are useful for:
- Multiline text
- SQL or HTML fragments
- Module, class, function, and method docstrings
def add(a, b): """Return the sum of two numbers.""" return a + bTriple quotes do not remove indentation or leading and trailing line breaks. If indentation affects the result, use textwrap.dedent() from the standard library.
3. Escape Sequences
A backslash gives the following character a special meaning. These are some common escape sequences:
| Sequence | Meaning |
|---|---|
\n | Newline |
\r | Carriage return |
\t | Horizontal tab |
\\ | One backslash |
\' | Single quote |
\" | Double quote |
\b | Backspace |
\0 | Null character, with code point zero |
\u4f60 | A Unicode character written with four hexadecimal digits—in this case, 你 |
print('Name: Bob\nAge: 18')Output:
Name: BobAge: 184. f-Strings: The Preferred Choice for Modern Python
Add f or F before a string to insert values or expressions inside {}. Python introduced f-strings in version 3.6:
name = 'Bob'age = 18
text = f'Name: {name}, age: {age}'print(text)The braces can contain expressions, including function and method calls:
a = 10b = 20name = 'bob'
print(f'{a} + {b} = {a + b}') # 10 + 20 = 30print(f'Name: {name.upper()}') # Name: BOBA colon after the expression introduces a format specifier:
{expression:format_specifier}4.1 Decimal Places, Thousands, and Percentages
price = 12.3456money = 1_234_567rate = 0.856
print(f'{price:.2f}') # 12.35print(f'{money:,}') # 1,234,567print(f'{rate:.1%}') # 85.6%.2fdisplays a fixed-point number with two decimal places.,adds a thousands separator..1%multiplies the value by 100, keeps one decimal place, and adds a percent sign.
4.2 Padding Numbers with Zeros
number = 7print(f'{number:03d}') # 007Here, d means a decimal integer, 3 sets the minimum field width, and 0 fills unused positions with zeros.
4.3 Alignment and Custom Fill Characters
name = 'Bob'
print(f'|{name:<10}|') # Left-alignedprint(f'|{name:^10}|') # Centeredprint(f'|{name:>10}|') # Right-alignedOutput:
|Bob || Bob || Bob|You can place a fill character before the alignment symbol:
print(f'|{name:-<10}|') # |Bob-------|print(f'|{name:-^10}|') # |---Bob----|print(f'|{name:->10}|') # |-------Bob|The pattern is fill character + alignment + field width. The symbols <, ^, and > mean left-aligned, centered, and right-aligned. Width is a minimum; longer values are not truncated.
This syntax can produce simple text tables:
print(f'{"Name":<10}{"Age":>5}')print(f'{"Bob":<10}{18:>5}')print(f'{"Alice":<10}{20:>5}')Python measures width in characters, while terminals arrange text in display cells. CJK characters, full-width characters, and some emoji may occupy two cells, so perfect visual alignment is not guaranteed.
4.4 Printing Literal Braces
Braces mark expressions inside an f-string. To print the braces themselves, double them as {{ or }}:
name = 'Bob'
print(f'{name}') # Bobprint(f'{{name}}') # {name}4.5 Debugging Expressions
Python 3.8 and later support = as a concise way to print both an expression and its value:
items = 3price = 12.5
print(f'{items=}, {price=}, {items * price=}')Output:
items=3, price=12.5, items * price=37.55. Raw Strings: The r Prefix
The r or R prefix creates a raw string. Backslashes in its literal text are generally preserved:
normal = 'hello\nworld'raw = r'hello\nworld'
print(normal)print(raw)Output:
helloworldhello\nworldRaw strings are especially useful for regular expressions:
import re
pattern = re.compile(r'\d+\.\d+')They can also make Windows paths easier to read:
path = r'C:\Users\Bob\Desktop'However, “raw” does not mean that backslashes play no role during parsing:
- A raw string cannot end with an odd number of consecutive backslashes.
- A quote matching the outer delimiter must still be protected with a backslash; that backslash remains in the result.
- A raw string does not turn a real line break into the two characters
\n.
The following code is invalid:
# SyntaxError: the string ends with a single backslashpath = r'C:\Users\Bob\'If a path must end with a backslash, join it with a regular string. Better still, use pathlib.Path for file-system paths.
6. Byte Literals: The b Prefix
The b or B prefix creates bytes, not str:
text = 'Hello'data = b'Hello'
print(type(text)) # <class 'str'>print(type(data)) # <class 'bytes'>The two types serve different purposes:
strrepresents Unicode text.bytesrepresents byte values from 0 to 255, used for network protocols, binary files, images, audio, compression, and cryptography.
Convert text to bytes with an explicit encoding, and decode the bytes with the matching encoding:
text = 'Hello, Python!'data = text.encode('utf-8')restored = data.decode('utf-8')
print(data) # b'Hello, Python!'print(restored) # Hello, Python!The source text of a byte literal may contain only ASCII characters. For example, b'你好' is invalid. Encode a str instead, or use \xhh escapes to specify exact byte values.
7. Unicode and the u Prefix
Regular strings are already Unicode strings in Python 3, so these forms are equivalent:
text1 = u'Hello'text2 = 'Hello'The u prefix mainly remains for compatibility with older code that once supported Python 2 and Python 3. New Python 3 code rarely needs it.
8. Combining String Prefixes
8.1 fr and rf
The f and r prefixes can be combined. fr and rf are equivalent:
name = 'Bob'path = rf'C:\Users\{name}\Desktop'
print(path) # C:\Users\Bob\DesktopHere, f evaluates {name}, while r preserves backslashes in the literal parts. This is also useful for dynamic regular expressions:
import re
word = 'hello'pattern = re.compile(rf'\b{re.escape(word)}\b')Use re.escape() for dynamic input so that regex metacharacters in the value do not change the pattern’s meaning. The r prefix affects the literal parts of an f-string; it does not apply raw-string processing to values produced inside {}.
8.2 br and rb
The b and r prefixes can also be combined. br and rb are equivalent:
data1 = br'\n'data2 = rb'\n'
print(data1) # b'\\n'print(data2) # b'\\n'Each result contains two bytes—a backslash and the letter n—rather than a newline byte. Prefixes cannot be combined freely: an f-string produces text, so bf'...' and fb'...' are invalid.
9. Other Formatting Styles
9.1 str.format()
str.format() remains common in older projects and in code that reuses format templates:
name = 'Bob'age = 18
text1 = 'Name: {}, age: {}'.format(name, age)text2 = 'Name: {name}, age: {age}'.format(name=name, age=age)price = 'Price: {:.2f}'.format(12.3456)It supports essentially the same format-specifier language as f-strings.
9.2 % Formatting
This is an older style of string formatting:
name = 'Bob'age = 18price = 12.3456
print('Name: %s, age: %d' % (name, age))print('Price: %.2f' % price)Common placeholders include %s for a string, %d for a decimal integer, %f for a floating-point number, and %x for a hexadecimal integer. For most new code, f-strings are clearer and more capable.
Python’s logging module is an important exception:
import logging
logging.info('User %s logged in', name)This parameterized form lets the logging system delay interpolation until needed. Do not replace it with an f-string merely for consistency.
10. Everyday String Methods
Strings are immutable. The following methods return new strings; they do not modify the original value.
Changing Case
text = 'Hello World'
print(text.lower()) # hello worldprint(text.upper()) # HELLO WORLDprint(text.title()) # Hello WorldRemoving Characters from the Ends
text = ' hello '
print(text.strip())print(text.lstrip())print(text.rstrip())With no argument, these methods remove whitespace. With an argument, they remove any combination of the characters in that argument—not one exact prefix or suffix.
Replacing Text
text = 'Hello Bob'result = text.replace('Bob', 'Alice')
print(result) # Hello AliceSplitting and Joining
text = 'apple,banana,orange'fruits = text.split(',')
print(fruits) # ['apple', 'banana', 'orange']print(','.join(fruits)) # apple,banana,orangeThe separator calls join(), and every item in the iterable must be a string.
Testing Content
text = 'Hello Python'
print(text.startswith('Hello')) # Trueprint(text.endswith('Python')) # Trueprint('Python' in text) # True11. Choosing the Right Form
| Use case | Recommended form |
|---|---|
| Regular text | '...' or "..." |
| Multiline text or a docstring | '''...''' or """...""" |
| Values or expressions inside text | f'...{value}...' |
| Regular expression | r'...' |
| Dynamic regular expression | rf'...', often with re.escape() |
| Binary data | b'...' or str.encode() |
| File-system path | Prefer pathlib.Path |
| Parameterized logging | logging.info('... %s', value) |
The main forms can be summarized in a few lines:
'hello' # Regular string"hello" # Regular string"""multiline string""" # Multiline stringf'hello {name}' # Formatted stringr'\d+\.\d+' # Raw string, often used for regexb'hello' # Byte literalrf'\b{re.escape(name)}\b' # Raw and formatted stringThe choice becomes straightforward once you separate the decisions. First decide whether you are working with text or bytes. Then ask whether you need escapes, multiple lines, or interpolation. From there, choose the simplest form that expresses your intent clearly.