Python Strings: Creating, Indexing and Slicing
A string is an immutable ordered sequence of characters. Indexing reaches one character, slicing reaches a range, and negative numbers count from the right.
- Basics
- Data Types
- Operators
- Strings
- Control Flow
- Lists
- Tuples
- Sets
- Dictionaries
- Comprehensions
- Functions
- Advanced Functions
- Recursion
- Exception Handling
- File Handling
- Modules
- Standard Library
- OOP
- Advanced OOP
- Iterators and Generators
- Decorators
- Context Managers
- Descriptors and Dataclasses
- Python Internals
- Concurrency
- Regular Expressions
- Serialization
- Command Line Python
- Testing and Debugging
- Type Hints
- Performance
- Python Security
- DSA with Python
Creating strings
single = 'Python'
double = "Python"
mixed = "It's fine" # double quotes let you keep the apostrophe
escaped = 'It\'s fine' # or escape it
triple = """A string that
spans several lines
without any escaping."""Single and double quotes are identical in meaning. Choose whichever avoids escaping. Triple quotes preserve line breaks exactly and are also how docstrings are written.
Escape sequences
| Sequence | Meaning |
|---|---|
\n | Newline |
\t | Tab |
\\ | A single backslash |
\' \" | A quote inside the same kind of quote |
\u20b9 | A character by its Unicode code point |
print("Line one\nLine two")
print("Name:\tMeera")
print("C:\\Users\\Admin") # one backslash each in the output
print("\u20b9250") # a rupee sign followed by 250Raw strings
path = r"C:\Users\Admin\notes" # backslashes stay literal
pattern = r"\d+\s\w+" # essential for regular expressions
print(path)
print(len("\n"), len(r"\n")) # 1 2A raw string turns off escape processing. It is the normal way to write file paths on Windows and regular expression patterns anywhere.
Indexing
text = "Python"
print(text[0]) # P
print(text[3]) # h
print(text[-1]) # n last character
print(text[-2]) # o
# print(text[10]) # IndexError: string index out of range P y t h o n
0 1 2 3 4 5 forward index
-6 -5 -4 -3 -2 -1 backward indexIndexing always returns a string of length one. Python has no separate character type.
Slicing
The form is text[start:stop:step]. start is included, stop is excluded.
text = "Programming"
print(text[0:7]) # Program
print(text[:7]) # Program - start defaults to 0
print(text[7:]) # ming - stop defaults to the end
print(text[:]) # Programming - a full copy
print(text[-4:]) # ming
print(text[:-4]) # Program
print(text[::2]) # Pormig - every second character
print(text[::-1]) # gnimmargorP - reversedSlicing never raisesIndexError."abc"[10:20]quietly returns"". Indexing out of range does raise. That asymmetry is intentional and worth remembering.
Why stop is excluded
text = "Programming"
print(len(text[0:7])) # 7 - the length equals stop minus start
print(text[:3] + text[3:]) # Programming - the two halves reassemble exactlyBoth properties fail if stop were included. This is the same convention range() uses.
Slicing with a negative step
text = "Programming"
print(text[::-1]) # gnimmargorP
print(text[5:1:-1]) # marg - walks backwards from index 5 down to 2
print(text[::-2]) # gimagrImmutability
text = "hello"
# text[0] = "H" # TypeError: 'str' object does not support item assignment
text = "H" + text[1:] # build a new string instead
print(text) # Hello
original = "hello"
upper = original.upper()
print(original, upper) # hello HELLO - the original is untouchedEvery string method returns a new string. None of them modifies the original, because none of them can. Forgetting to assign the result is the single most common string mistake:
name = " meera "
name.strip() # the result is computed and thrown away
print(repr(name)) # ' meera ' - unchanged
name = name.strip() # correct
print(repr(name)) # 'meera'Length and iteration
text = "Python"
print(len(text)) # 6
for character in text:
print(character, end=" ")
print()
for index, character in enumerate(text):
print(index, character)Strings are Unicode
text = "नमस्ते"
print(len(text)) # counts code points, not bytes
print(ord("A")) # 65
print(chr(65)) # A
print(ord("₹")) # 8377
encoded = "café".encode("utf-8")
print(encoded) # b'caf\xc3\xa9'
print(len("café"), len(encoded)) # 4 5
print(encoded.decode("utf-8")) # caféA Python 3 string is a sequence of Unicode code points. Bytes are a different type, produced by encode and turned back by decode. Files and networks carry bytes; your program works in text. Convert at the boundary and nowhere else.
Common mistakes
- Calling a string method and not assigning the result.
- Trying to assign to
text[0]. - Expecting
text[0:5]to include index 5. - Writing a Windows path without a raw string, so
\\nor\\tbecomes a control character. - Confusing
lenof a string with the number of bytes it occupies. - Building a long string by repeated
+=in a loop; use"".join(parts)instead.
Best practices
- Pick one quote style per project and switch only to avoid escaping.
- Use raw strings for paths and regular expression patterns without exception.
- Use slicing rather than a loop when you want a portion of a string.
- Remember that
text[:]is a copy, and that copying an immutable object is rarely necessary. - Decode bytes into text as early as possible, encode as late as possible.
Practice
- Given
"Programming", produce"gram","Pormig","gnimmargorP"and"ming"with slices only. - Write a function that checks whether a word is a palindrome, ignoring case, in one line.
- Explain why
"abc"[5]raises but"abc"[5:9]does not. - Print the first and last three characters of any string, handling strings shorter than six characters sensibly.
- Explain the difference between
len("café")andlen("café".encode("utf-8")).
Conclusion
Strings are immutable sequences. Index for one character, slice for a range, remember that stop is excluded and that slices never raise, and always assign the result of a string method to something.