Python Strings

Everything about strings in one place โ€” creation, indexing & slicing, immutability, operators, and the full built-in method toolbox.

Table of Contents

  1. Creating Strings
  2. Indexing & Slicing
  3. Editing & Deleting Strings
  4. String Operations
  5. String Functions

Part 1Creating Strings

Overview

Strings in Python are a sequence of Unicode characters. This part covers the different ways you can create a string in Python, the quirks around quote characters, and how to build multi-line strings.

Key Concepts

1. Creating Strings โ€” Basic Ways

Using single quotes

# Creating
c = 'Hello'
print(c)
Hello

Using double quotes

c = "Hello"
print(c)
Hello

Point to remember: Single and double quotes behave the same for simple strings โ€” the choice mostly matters when the string itself contains a quote character.

2. The Apostrophe Problem

If you try to write a string containing an apostrophe using single quotes, Python gets confused about where the string ends:

'It's raining outside'
File "<ipython-input-16-7f9c68e857c8>", line 1
    'It's raining outside'
        ^
SyntaxError: invalid syntax

Why this happens: Python reads the first ' as the start of the string and the ' in It's as the end of the string. Everything after that (s raining outside') becomes invalid code, causing a SyntaxError.

The fix โ€” use double quotes instead

c = "It's raining outside"

Because the string is now delimited by ", the apostrophe inside it is treated as a normal character, not a string terminator.

Tip: As a rule of thumb โ€” if your string contains an apostrophe ('), wrap it in double quotes "...". If it contains a double quote ("), wrap it in single quotes '...'.

3. Triple-Quoted Strings

Triple quotes can use either three single quotes or three double quotes:

c = '''Hello'''
print(c)
Hello
c = """Hello"""
print(c)
Hello

For a simple one-word string, triple quotes behave just like single/double quotes.

Triple quotes โ†’ Multi-line strings

The real power of triple quotes is writing multi-line strings directly in the source code:

c = '''Hello'''
print(c)
# multi line strings
โš ๏ธ Screenshot text unclear โ€” the instructor was in the middle of typing a comment (# multi line strings) while demonstrating that triple-quoted strings support multi-line text; the exact multi-line example content wasn't fully visible in the screenshots.

Important points:

4. Creating Strings with str()

You can also explicitly create a string using the built-in str() function:

c = str("Hello")
c
Out: 'Hello'

Note: str() is more commonly used to convert other data types (numbers, lists, etc.) into strings, but it can also just wrap an existing string.

Things to Remember

Quick Revision

Python lets you create strings with single quotes, double quotes, or triple quotes โ€” they're mostly interchangeable for simple text. The catch: if your string contains the same quote character used to wrap it (e.g., an apostrophe inside '...'), Python throws a SyntaxError because it thinks the string ended early. Fix this by switching to the other quote type. Triple quotes (''' or """) are the go-to choice for multi-line strings. You can also build a string using the str() function.


Part 2Indexing & Slicing

Overview

Since a string is a sequence of characters, each character has a position (index). This part covers:

  1. Indexing โ€” accessing a single character from a string.
  2. Slicing โ€” extracting a substring (a range of characters) from a string.

1. Indexing

Basic Indexing

# Concept of Indexing
c = "hello"
print(c)
hello

Every character in a string has a numeric position, starting from 0 for the first character.

print(c[4])
o

c[4] picks the character at index 4. For "hello" (h-e-l-l-o), index 4 is 'o'.

Out-of-range Index โ†’ IndexError

print(c[5])
IndexError: string index out of range

Why: "hello" has 5 characters, so valid indices are 0 to 4. Index 5 doesn't exist.

โš ๏ธ Important: String indices are always 0-based. For a string of length n, valid positive indices go from 0 to n-1.
print(c[0])
h

c[0] always gives the first character of the string.

Types of Indexing

Python supports two ways to index a string:

TypeDirectionExample (for "hello")
Positive IndexingCounts from the start (left โ†’ right), beginning at 0c[0] โ†’ h, c[4] โ†’ o
Negative IndexingCounts from the end (right โ†’ left), beginning at -1c[-1] โ†’ o, c[-2] โ†’ l

Index map for "hello":

Characterhello
Positive index01234
Negative index-5-4-3-2-1
# Types of Indexing
# Positive Indexing
# Negative Indexing
print(c[-2])
l

c[-2] accesses the 2nd character from the end โ†’ 'l'.

print(c[-4])
l
โš ๏ธ Screenshot text unclear โ€” based on the index map above, c[-4] on "hello" should return 'e', but the screenshot's visible output looked like 'l'. Please re-verify this specific output by running the code yourself.

Important points on indexing:

2. Slicing

Slicing lets you extract a substring using the syntax:

string[start : stop : step]

Basic Slicing

# Slicing
c = "Hello World"
print(c)
Hello World
print(c[0:4])
Hell

Takes characters from index 0 up to (but not including) index 4.

print(c[0:5])
Hello

Omitting start or stop

print(c[2:])
llo World

Leaving stop empty means "go all the way to the end."

print(c[:4])
Hell

Leaving start empty means "start from the beginning."

print(c[:])
Hello World

Leaving out both start and stop returns the entire string โ€” this is a common way to make a copy of a string.

print(c)
Hello World

(Confirms c itself is unchanged โ€” slicing doesn't modify the original string, it just returns a new one.)

Slicing with a step

print(c[0:8:3])
HlW

With step = 3, Python picks characters at indices 0, 3, 6 โ†’ H, l, W.

Note: In the video, the instructor first ran this slice and got a different/incomplete result before re-running it correctly to get HlW โ€” a good reminder to always double check your slice indices against the string's actual character positions.

Step direction matters

print(c[0:6:-1])
โš ๏ธ Screenshot text unclear โ€” no output was visible for this line in the screenshots (it may print an empty string). This happens because with a negative step, Python expects start to be greater than stop (moving right to left); here start=0 and stop=6 go the "wrong way" for a negative step, so no characters are returned.
print(c[-5:-1:2])
Wr

Using negative indices as start/stop: -5 corresponds to 'W' and it steps forward by 2 up to (but excluding) index -1, picking 'W' and 'r'.

Reversing a String

print(c[::-1])
dlroW olleH

This is the classic Python trick to reverse a string. With start and stop omitted and step = -1, Python walks the entire string backward, one character at a time.

print(c[-1:-5:-1])
dlro

Starting at the last character (-1 = 'd') and stepping backward (step = -1) down to (but excluding) -5 ('W'), giving 'd', 'l', 'r', 'o'.

Things to Remember

Quick Revision

Indexing (c[i]) fetches a single character โ€” positive indices count from the left starting at 0, negative indices count from the right starting at -1; going out of range throws an IndexError. Slicing (c[start:stop:step]) extracts a substring: start is inclusive, stop is exclusive, and step controls the jump size and direction. Omitting parts of the slice gives sensible defaults (start of string, end of string, or the whole string with c[:]). The step can be negative to move backward โ€” and c[::-1] is the classic one-liner to reverse an entire string.


Part 3Editing & Deleting Strings

Overview

This part answers a key question: can you edit or delete characters inside a string directly? The short answer is no โ€” and the reason why is one of the most important properties of Python strings: they are immutable.

Key Concepts

1. Editing Strings โ€” Why It Fails

c = "Hello"
print(c)
Hello

Trying to change the first character:

c[0] = 'X'
TypeError: 'str' object does not support item assignment

Why: Strings don't support item assignment. You cannot reach into a string and overwrite one of its characters the way you can with a list (my_list[0] = 'X' would work fine for a list).

# Strings are a Immutable Data Type
c = "world"
print(c)
world

Trying again with a different index:

c[5] = "X"
TypeError: 'str' object does not support item assignment
Note: It doesn't matter which index you try (0, 5, etc.) โ€” no index of a string can ever be reassigned, because the string object itself is immutable.

If you need a "modified" string...

Since strings can't be edited in place, the standard approach is to create a new string โ€” e.g., using slicing/concatenation, or string methods (covered in Part 5) โ€” and assign it back to the variable if needed.

2. Deleting Parts of a String โ€” Why It Also Fails

# Deletion
c
Out: 'world'

Trying to delete a single character:

del c[0]
TypeError: 'str' object doesn't support item deletion

Trying to delete a slice of characters:

del c[:3:2]
TypeError: 'str' object does not support item deletion

Why: Just like item assignment, item deletion isn't supported on strings โ€” you cannot remove a character (or a range of characters) from a string in place, for the same immutability reason.

3. Deleting the Entire Variable

While you can't delete part of a string, you can delete the variable that points to it entirely, using del:

del c

After this, the variable c no longer exists:

print(c)
NameError: name 'c' is not defined

Why: del c removes the variable binding itself from memory โ€” it's not modifying the string object, it's just deleting the name that referred to it.

Things to Remember

Quick Revision

Python strings are immutable: you cannot assign a new character to an index (c[0] = 'X' โ†’ TypeError: item assignment), and you cannot delete a character or slice from a string (del c[0] โ†’ TypeError: item deletion). The only thing you can delete is the variable name itself (del c), after which trying to use that variable raises a NameError. If you need a modified version of a string, you must always create a new string โ€” the original object can never be changed in place.


Part 4String Operations

Overview

This part covers the different operators you can use directly on strings:

1. Arithmetic Operations

Strings support two arithmetic-style operators: + (concatenation) and * (repetition).

Concatenation (+)

"Hello" + "world"
Out: 'Helloworld'

Note: + simply glues the strings together character-for-character โ€” it does not insert a space automatically.

"Hello" + "-" + "world"
Out: 'Hello-world'

You can chain multiple + operators to join several strings (and any literal characters, like "-", in between).

Repetition (*)

print("*" * 50)
**************************************************
print("Hello" * 4)
HelloHelloHelloHello

Note: string * n repeats the entire string n times, back-to-back with no separator.

2. Relational Operations

Strings can be compared with ==, !=, <, >, <=, >= โ€” just like numbers.

"Hello" == "World"
Out: False
"Hello" != "WOrld"
Out: True

Comparing with < and > โ€” Lexicographic (Dictionary) Order

"Mumbai" > "Pune"
# Lexiographically
Out: False
"Goa" < "Kolkata"
Out: True

How it works: String comparisons are done lexicographically (like dictionary/alphabetical order) โ€” Python compares characters one by one based on their underlying Unicode/ASCII values, until it finds a difference.

The Case-Sensitivity Trap

"kol" < "Kol"
Out: False

Why: String comparison is case-sensitive. In ASCII/Unicode, lowercase letters have higher numeric values than their uppercase counterparts ('k' > 'K'). So "kol" (starting with lowercase k) is actually considered greater than "Kol" (starting with uppercase K) โ€” which is why "kol" < "Kol" evaluates to False.

โš ๏ธ Important: Never assume string comparisons ignore case โ€” "apple" == "Apple" is False, and sorting/comparing mixed-case strings can give unintuitive results unless you normalize case first (e.g., with .lower()).

3. Logical Operations

Python's and, or, and not work on strings too, based on truthy/falsy values.

Truthy vs Falsy Strings

StringTruthy/Falsy
"" (empty string)Falsy โ†’ False
Any non-empty string (e.g., "wreghr")Truthy โ†’ True
not ""
Out: True
print(not "hello")
False

not simply flips the truthy/falsy value โ€” since "hello" is truthy, not "hello" is False; since "" is falsy, not "" is True.

and and or Return a Value, Not Just True/False

Unlike == or <, the and/or operators on strings return one of the operands themselves, not a plain boolean.

"hello" and "world"
Out: 'world'

Rule for and: If the first operand is truthy, Python evaluates and returns the second operand. (If the first operand were falsy, and would short-circuit and return the first operand instead.)

"" and "Hello"
Out: ''

Here, "" is falsy, so and short-circuits immediately and returns the first operand ("") without even looking at "Hello".

"" or "world"
Out: 'world'

Rule for or: If the first operand is falsy, Python moves on and returns the second operand.

"hello" or "world"
Out: 'hello'

Here, "hello" is truthy, so or short-circuits immediately and returns the first operand ("hello") without evaluating "world".

๐Ÿ’ก Quick mental model:

4. Loops on Strings

Since a string is a sequence, you can iterate over it directly with a for loop โ€” each iteration gives you one character.

c = "hello world"
for i in c:
    print(i)
h
e
l
l
o

w
o
r
l
d

Note: The loop prints every character, including the space between "hello" and "world" (shown above as a blank line).

Combining Loops with Slicing

You can loop over a slice of the string instead of the whole thing:

c = "hello world"
for i in c[2:7:2]:
    print(i)
l
o
w

This loops only over the characters picked out by the slice c[2:7:2] (start=2, stop=7, step=2) โ€” i.e., indices 2, 4, 6 โ†’ 'l', 'o', 'w'.

โš ๏ธ Screenshot text unclear โ€” one screenshot showed a loop's output printing characters vertically (w, o, l, l, e, h), but the exact code that produced it wasn't visible. It appeared to demonstrate looping over a reversed or sliced version of the string, similar to the pattern above โ€” worth re-running examples like for i in c[::-1]: print(i) yourself to see reversed iteration in action.

5. Membership Operations (in / not in)

These check whether a character (or substring) exists inside a string, returning True or False.

'h' in c
Out: True
'H' in c
Out: False

Note: Just like relational operations, membership checks are case-sensitive โ€” 'h' and 'H' are treated as different characters.

'world' not in c
Out: False

Reading this carefully: 'world' not in c is False because 'world' is actually present in c โ€” not in returns True only when the item is absent.

'n' in c
Out: True

Things to Remember

Quick Revision

Strings support arithmetic-style operators: + concatenates and * repeats. Relational operators compare strings lexicographically using character ASCII values โ€” and remember, comparisons are case-sensitive (lowercase > uppercase in ASCII). Logical operators (and, or, not) work using truthy/falsy rules ("" is falsy, everything else is truthy) and โ€” unlike numeric comparisons โ€” and/or return one of the actual operand strings rather than a plain boolean. You can loop directly over a string's characters with for i in string:, optionally combined with slicing. Finally, in / not in let you check membership of a character or substring, again case-sensitively.


Part 5String Functions

Overview

Python strings come with a large set of built-in methods (functions attached to the string object, called with string.method()). This part walks through the most commonly used ones: general-purpose functions, case conversion, counting, searching, checks, formatting, splitting, joining, replacing, and stripping whitespace.

Common (Built-in) Functions

These aren't string methods โ€” they're general Python functions that happen to work well on strings:

c = "kolkata"
len(c)
Out: 7

len() returns the number of characters in the string.

max(c)
Out: 't'
min(c)
Out: 'a'

max()/min() return the character with the highest/lowest Unicode value in the string.

sorted(c)
Out: ['a', 'a', 'k', 'k', 'l', 'o', 't']
sorted(c, reverse=True)
Out: ['t', 'o', 'l', 'k', 'k', 'a', 'a']

sorted() returns a list of the string's characters in sorted order (ascending by default; pass reverse=True for descending).

1. Capitalize / Title / Upper / Lower / Swapcase

"it is raining today".capitalize()
Out: 'It is raining today'

.capitalize() uppercases only the first letter of the whole string, lowercasing the rest.

"it is raining today".title()
Out: 'It Is Raining Today'

.title() uppercases the first letter of every word.

c = "kolkata"
c.upper()
Out: 'KOLKATA'
c.upper().lower()
Out: 'kolkata'

.upper() / .lower() convert the entire string to upper/lower case. Methods can be chained โ€” .upper().lower() calls .lower() on the result of .upper().

"KoLkAtA".swapcase()
Out: 'kOlKaTa'

.swapcase() flips the case of every character โ€” upper becomes lower and vice versa.

2. Count

"it is raining".count("x")
Out: 0
"it is raining".count("i")
Out: 4
"it is raining".count("is")
Out: 1
"it is raining".count("ing")
Out: 1

.count(sub) returns how many non-overlapping times sub appears in the string.

3. Find / Index

"it is raining".find("x")
Out: -1
"it is raining".find("g")
Out: 12
"it is raining".index("x")
ValueError: substring not found
"it is raining".index("rain")
Out: 6

Key difference between .find() and .index():

MethodSubstring foundSubstring NOT found
.find(sub)Returns the starting indexReturns -1
.index(sub)Returns the starting indexRaises ValueError: substring not found
๐Ÿ’ก Use .find() when a missing substring is a normal case you want to handle gracefully; use .index() when you'd rather the program fail loudly if the substring is expected to be there.

4. endswith / startswith

"it is raining".endswith("ing")
Out: True
"it is raining".endswith("ingef")
Out: False
"it is raining".startswith("it")
Out: True

These check whether the string ends with or begins with a given substring, returning True/False.

5. format

.format() lets you build strings with placeholders ({}) that get filled in with values.

"Hello my name is {} and I am {}".format("Nitish", 30)
Out: 'Hello my name is Nitish and I am 30'

Empty {} placeholders are filled in order by the arguments passed to .format().

"Hello my name is {1} and I am {0}".format("Nitish", 30)
Out: 'Hello my name is 30 and I am Nitish'

You can put a positional index inside {} to control which argument fills which placeholder โ€” {1} refers to the 2nd argument (30), {0} to the 1st ("Nitish").

"Hello my name is {age} and I am {name}".format(name="Nitish", age=30)
Out: 'Hello my name is 30 and I am Nitish'

You can also use named placeholders matched to keyword arguments โ€” note the placeholder name doesn't have to "make sense" relative to the value; Python just matches the placeholder name to the keyword argument name.

"Hello my name is {age} and I am {weight}".format(name="Nitish", age=30, weight=70)
Out: 'Hello my name is 30 and I am 70'

Extra keyword arguments that aren't referenced by any {} placeholder (like name here) are simply ignored.

6. isalnum / isalpha / isdecimal / isdigit / isidentifier

These all return True/False checks about what kind of characters a string contains.

"FLAT20&".isalnum()
Out: False

.isalnum() checks if all characters are letters or digits โ€” fails here because of &.

"FLAT20".isalpha()
Out: False

.isalpha() checks if all characters are letters โ€” fails here because of the digits 2, 0.

"20A".isdigit()
Out: False

.isdigit() checks if all characters are digits โ€” fails here because of the letter A.

"hello world".isidentifier()
Out: False
"hello_world".isidentifier()
Out: True

.isidentifier() checks whether the string would be a valid Python variable name โ€” spaces aren't allowed (so "hello world" fails), but underscores are fine (so "hello_world" passes).

๐Ÿ’ก isdecimal() is also part of this family (not shown running here) โ€” it's similar to isdigit() but stricter about which numeric characters count as "decimal."

7. Split

"who is the pm of india".split()
Out: ['who', 'is', 'the', 'pm', 'of', 'india']

With no argument, .split() breaks the string into a list of words, splitting on any whitespace.

"who is the pm of india".split("i")
Out: ['who ', 's the pm of ', 'nd', 'a']

Passing a separator splits on every occurrence of that exact substring, removing it from the result.

"who is the pm of india".split("x")
Out: ['who is the pm of india']

If the separator doesn't appear anywhere in the string, .split() returns a list containing the entire original string as its only element.

8. Join

.join() is the reverse of .split() โ€” it combines a list of strings into one string, using the string it's called on as the separator.

" ".join(['who', 'is', 'the', 'pm', 'of', 'india'])
Out: 'who is the pm of india'
"/".join(['who', 'is', 'the', 'pm', 'of', 'india'])
Out: 'who/is/the/pm/of/india'
"-".join(['who', 'is', 'the', 'pm', 'of', 'india'])
Out: 'who-is-the-pm-of-india'

Whatever string .join() is called on becomes the glue placed between every element of the list.

9. Replace

"Hi my name is Nitish".replace("Nitish", "Amit")
Out: 'Hi my name is Amit'

.replace(old, new) returns a new string with every occurrence of old swapped for new.

10. Strip

name = "          nitish          "
name.strip()
Out: 'nitish'

.strip() removes leading and trailing whitespace (spaces, tabs, newlines) from a string โ€” it does not touch whitespace in the middle.

๐Ÿ’ก Related methods (seen via autocomplete, not individually demonstrated): .lstrip() strips only from the left, .rstrip() strips only from the right. Other string methods available include .partition(), .rpartition(), .rfind(), .rindex(), .rjust(), .rsplit(), and .maketrans() โ€” worth exploring in the Python docs or via tab-autocomplete in a notebook.

Things to Remember

Quick Revision

Strings have a rich set of built-in methods. For case handling: .capitalize(), .title(), .upper(), .lower(), .swapcase(). For searching: .count() counts matches, .find() returns -1 if not found while .index() raises an error, and .startswith()/.endswith() check prefixes/suffixes. .format() builds strings from placeholders filled positionally, by index, or by keyword. The is...() methods (isalnum, isalpha, isdigit, isidentifier, etc.) validate what kind of characters a string contains. .split() turns a string into a list of pieces; .join() does the reverse. .replace() swaps substrings, and .strip() (plus .lstrip()/.rstrip()) trims whitespace from the ends.