Data Structures

Python List — Complete Beginner to Interview Guide

Learn Python lists from scratch: every method explained one by one with example code and output, plus interview patterns explained question-first, solution-second.

  • Python
  • List
  • DSA
  • Data Structures
  • Algorithm

1. What is a List?

A list is one of the most commonly used data structures in Python.

In simple words:

  1. A list is a container that holds multiple items in a single variable.
  2. Think of it like a shopping list — you can add items, remove items, or check what’s on it.
  3. A list is ordered — the items stay in the order you put them in.
  4. A list is mutable — you can change it after creating it (add, remove, update items).
  5. A list can hold mixed data types — numbers, text, even other lists, all in the same list.
  6. Internally, Python stores a list as a dynamic array of pointers — it automatically grows in size as you add more items.
what_is_a_list.py

2. Creating a List (Every Way, One by One)

2.1 Creating an Empty List

empty_list.py

2.2 Creating a List With Values

list_with_values.py

2.3 Creating a List Using list()

list_constructor.py

2.4 Creating a List by Repeating a Value

repeat_list.py

3. Accessing List Elements (Indexing)

Points to remember:

  1. Every item in a list has a position number called an index.
  2. Indexing starts from 0, not 1. The first item is at index 0.
  3. You can also count from the end using negative numbers: -1 is the last item, -2 is second-last, and so on.
  4. If you use an index that doesn’t exist, Python raises an IndexError.
indexing.py
Positive index (left to right)“apple”index 0“banana”index 1“mango”index 2“orange”index 3index -4index -3index -2index -1

4. List Slicing

Slicing means taking out a piece of the list instead of a single item.

Syntax: my_list[start : stop : step]

Points to remember:

  1. start is where the slice begins (included).
  2. stop is where the slice ends (not included).
  3. step is how many items to skip each time (default is 1).
  4. All three parts are optional.
slicing_basic.py
slicing_step.py

Beginner tip: Slicing never crashes your program even if the numbers are “out of range”:

slicing_safe.py

5. Basic List Operations

5.1 Finding the Length — len()

len_example.py

5.2 Checking Membership — in and not in

membership.py

5.3 Joining Two Lists — +

concatenation.py

5.4 Repeating a List — *

repetition.py

6. Lists Are Mutable (You Can Change Them)

mutability.py

7. Every List Method — Explained One by One

Below is every built-in list method. Each one has its own explanation, syntax, and example with output.

7.1 append(x) — Add One Item to the End

Points:

  1. Adds a single item to the end of the list.
  2. Changes the list in place — it does not return a new list.
  3. Very fast — O(1) on average.
append_method.py

7.2 insert(index, x) — Add an Item at a Specific Position

Points:

  1. Inserts x before the given index.
  2. Every item after that index shifts one position to the right.
  3. Slower than append() — O(n), because of the shifting.
insert_method.py

7.3 extend(iterable) — Add Many Items at Once

Points:

  1. Adds every item from another list (or any iterable) to the end.
  2. Different from append() — append() adds the whole thing as one item, extend() adds each item separately.
extend_method.py

7.4 remove(x) — Remove the First Matching Value

Points:

  1. Removes the first item that equals x.
  2. If x is not found, it raises a ValueError.
  3. It removes by value, not by index.
remove_method.py

7.5 pop(index) — Remove and Return an Item

Points:

  1. Removes the item at the given index and returns it.
  2. If no index is given, it removes the last item — this is the fast, O(1) case.
  3. Popping from the front (pop(0)) is slow — O(n) — because everything shifts left.
pop_method.py

7.6 clear() — Remove Everything

clear_method.py

7.7 index(x) — Find the Position of a Value

Points:

  1. Returns the index of the first occurrence of x.
  2. Raises a ValueError if x isn’t in the list.
index_method.py

7.8 count(x) — Count How Many Times a Value Appears

count_method.py

7.9 sort() — Sort the List In Place

Points:

  1. Sorts the list in ascending order by default.
  2. Changes the original list — does not return a new one (returns None).
  3. Use reverse=True to sort in descending order.
  4. Use key= to sort using a custom rule.
sort_method.py

7.10 reverse() — Reverse the List In Place

reverse_method.py

7.11 copy() — Make a Shallow Copy

copy_method.py

8. All Methods in One Table (Quick Reference)

Every list method at a glance
methodwhat it doestime complexity
append(x)Add x to the endO(1) average
insert(i, x)Insert x before index iO(n)
extend(iterable)Add each item of iterable to the endO(k) for k new items
remove(x)Remove first item equal to xO(n)
pop(i=-1)Remove & return item at index iO(1) at end, O(n) elsewhere
clear()Remove all itemsO(n)
index(x)Find index of first xO(n)
count(x)Count occurrences of xO(n)
sort()Sort in place, ascending by defaultO(n log n)
reverse()Reverse in placeO(n)
copy()Shallow copyO(n)

9. sort() vs sorted() and reverse() vs reversed()

Beginners mix these up all the time. Here is the difference, clearly:

Method vs Function — key differences
sort()sorted()
Changes original list?Yes (in place)No — returns a new list
Return valueNoneA new list
Works on any iterable?No — only listsYes — lists, tuples, strings, etc.
sort_vs_sorted.py
reverse_vs_reversed.py

10. Copying a List — Shallow Copy vs Deep Copy

Points to remember:

  1. Writing b = a does NOT copy the list — it just gives the same list a second name.
  2. A shallow copy (a.copy(), a[:], or list(a)) makes a new outer list, but if it contains other lists inside, those inner lists are still shared.
  3. A deep copy (copy.deepcopy(a)) makes a completely independent copy, including everything nested inside.
b = a (same list, two names)a ──┐[1, 2, 3]b ──┘b = a.copy() (new outer list, independent)a: [1, 2, 3]b: [1, 2, 3]← two SEPARATE lists now
reference_vs_copy.py
shallow_copy.py
shallow_copy_nested_problem.py
deep_copy.py

11. Nested Lists (2D Lists) — A Common Beginner Trap

Points:

  1. A “2D list” is just a list of lists — often used to represent a grid or table.
  2. [[0] * 3] * 4 looks like it makes 4 independent rows, but it does not — it repeats the same inner list 4 times!
  3. The correct way is to use a list comprehension, which creates a brand new inner list every time.
nested_list_bug.py
nested_list_fixed.py

12. List Comprehensions (Basic → Medium → Advanced)

A list comprehension is a short, one-line way to build a list.

Basic syntax: [expression for item in iterable]

12.1 Basic

comprehension_basic.py

12.2 Medium — With a Condition

Syntax: [expression for item in iterable if condition]

comprehension_condition.py

12.3 Advanced — Nested Comprehension

comprehension_nested.py

12.4 Advanced — if / else Inside a Comprehension

comprehension_if_else.py

13. Useful Built-in Functions That Work With Lists

13.1 enumerate() — Get Index and Value Together

enumerate_example.py

13.2 zip() — Walk Through Two Lists Together

zip_example.py

13.3 sum(), min(), max()

sum_min_max.py

13.4 collections.Counter — Counting Items Fast

counter_example.py

14. Using a List as a Stack or a Queue

Points:

  1. A stack follows Last-In-First-Out (LIFO) — the last item added is the first one removed.
  2. A queue follows First-In-First-Out (FIFO) — the first item added is the first one removed.
  3. A plain list makes a great stack (both append() and pop() at the end are fast, O(1)).
  4. A plain list makes a bad queue — removing from the front (pop(0)) is slow, O(n).
  5. For a queue, use collections.deque instead.
stack_example.py
queue_example.py

15. Time Complexity Cheat Sheet

Big-O for list operations — good to memorize
operationtime complexitywhy
a[i] (index access)O(1)Direct memory lookup
append(x)O(1) averageUsually just adds to the end
pop() (from end)O(1)No shifting needed
pop(0) (from front)O(n)Every other item shifts left
insert(0, x) (at front)O(n)Every other item shifts right
x in a (search)O(n)Checks items one by one
len(a)O(1)Length is stored, not recounted
sort()O(n log n)Timsort algorithm
a[i:j] (slicing)O(j - i)Copies the sliced part

16. Interview Patterns (Question First, Then Solution)

This section teaches you patterns that show up again and again in coding interviews. For each pattern, you will see:

  1. What the pattern is and when to use it.
  2. A real interview-style question.
  3. An example with input and expected output.
  4. A hint.
  5. The approach, explained in plain words.
  6. The final code, with output shown as comments.
  7. The time and space complexity.

16.1 Pattern: Two Pointers

What it is:

  1. Use two index variables (pointers) that move through the list — often from opposite ends, or one fast and one slow.
  2. Useful when you need to compare or swap items without using extra memory.
12321left ↑right ↑

❓ Interview Question:

  1. Problem: Given a list of numbers, check whether it reads the same forwards and backwards (a palindrome).
  2. Example:
    • Input: [1, 2, 3, 2, 1]
    • Expected Output: True
    • Input: [1, 2, 3, 4]
    • Expected Output: False
  3. Hint: Compare the first and last item, then move inward. If they ever don’t match, it’s not a palindrome.

✅ Approach:

  1. Set left = 0 and right = len(list) - 1.
  2. While left < right: compare list[left] and list[right].
  3. If they don’t match, return False immediately.
  4. Otherwise, move left forward by 1 and right backward by 1.
  5. If the loop finishes without mismatches, return True.
two_pointers_palindrome.py

Complexity: Time = O(n), Space = O(1) — no extra list is created.


16.2 Pattern: Sliding Window

What it is:

  1. Keep a “window” (a range of items) and slide it across the list, one step at a time.
  2. Useful for problems about subarrays of a fixed or changing size.
  3. Much faster than recomputing everything from scratch at every step.

❓ Interview Question:

  1. Problem: Given a list of numbers and a window size k, find the maximum sum of any k consecutive numbers.
  2. Example:
    • Input: nums = [2, 1, 5, 1, 3, 2], k = 3
    • Expected Output: 9 (from the subarray [5, 1, 3])
  3. Hint: Don’t recompute the sum from scratch every time — just subtract the item leaving the window and add the item entering it.

✅ Approach:

  1. Calculate the sum of the first k items — this is the starting window.
  2. Slide the window one step at a time: subtract the item that is leaving, add the item that is entering.
  3. Keep track of the biggest sum seen so far.
sliding_window_max_sum.py

Complexity: Time = O(n) — a single pass. Space = O(1).


16.3 Pattern: Prefix Sum

What it is:

  1. Precompute the running total up to each index, one time.
  2. After that, any “sum between index A and B” question can be answered instantly, without looping again.

❓ Interview Question:

  1. Problem: You are given a list of numbers, and you will be asked the sum of a range [left, right] many times. Answer each query as fast as possible.
  2. Example:
    • Input: nums = [1, 2, 3, 4, 5], query: sum of index 1 to 3
    • Expected Output: 9 (because 2 + 3 + 4 = 9)
  3. Hint: Build one extra list first, where each position stores the total sum “so far.”

✅ Approach:

  1. Build a prefix list where prefix[i] = sum of all numbers before index i.
  2. To get the sum from left to right, compute prefix[right + 1] - prefix[left].
  3. This turns every query into an O(1) lookup, after one O(n) setup step.
prefix_sum.py

Complexity: Building the prefix list = O(n). Each query after that = O(1).


16.4 Pattern: Kadane’s Algorithm (Maximum Subarray Sum)

What it is:

  1. A classic technique to find the largest possible sum of any contiguous subarray.
  2. Works even when the list has negative numbers.

❓ Interview Question:

  1. Problem: Given a list of numbers (which can include negative numbers), find the maximum possible sum of a contiguous subarray.
  2. Example:
    • Input: [-2, 1, -3, 4, -1, 2, 1, -5, 4]
    • Expected Output: 6 (from the subarray [4, -1, 2, 1])
  3. Hint: At each position, decide: should I extend the previous subarray, or start a brand new one from here?

✅ Approach:

  1. Keep two values: current_sum (best sum ending exactly at this position) and best_sum (best sum seen anywhere so far).
  2. At each number, decide: is it better to add this number to the running current_sum, or start fresh from this number alone?
  3. Update best_sum whenever current_sum beats it.
kadanes_algorithm.py

Complexity: Time = O(n), Space = O(1).


16.5 Pattern: Remove Duplicates From a Sorted List (Two Pointers, In Place)

❓ Interview Question:

  1. Problem: Given a sorted list, remove the duplicates in place so each value appears only once, and return the new length.
  2. Example:
    • Input: [1, 1, 2, 2, 3]
    • Expected Output: length 3, and the list becomes [1, 2, 3, ...] (only the first 3 positions matter)
  3. Hint: Use a “slow” pointer for where to write the next unique value, and a “fast” pointer to scan ahead.

✅ Approach:

  1. slow starts at index 0 — it marks the last confirmed unique value.
  2. fast scans through the rest of the list.
  3. Whenever nums[fast] is different from nums[slow], it’s a new unique value — move slow forward and copy it there.
remove_duplicates_sorted.py

Complexity: Time = O(n), Space = O(1) — done in place, no extra list.

17. Practice Problems (Try These Yourself)

  1. Find the second-largest number in a list, without using sort().
  2. Rotate a list to the right by k steps.
  3. Find all pairs in a list that add up to a given target number.
  4. Merge two already-sorted lists into one sorted list.
  5. Find the missing number in a list containing 1 to n with one number missing.

18. Key Takeaways

  1. A list is an ordered, mutable, resizable container — Python’s most flexible built-in data structure.
  2. Indexing starts at 0; negative indexes count from the end.
  3. sort()/reverse() change the list in place and return None; sorted()/reversed() return a new result and leave the original untouched.
  4. a.copy() only copies one level deep — for nested lists, use copy.deepcopy().
  5. [[0]*3] * 4 shares the same inner list across every row — always build 2D lists with a comprehension instead.
  6. Lists are great stacks (fast at the end) but bad queues (slow at the front) — use collections.deque for queues.
  7. Two pointers, sliding window, prefix sums, and Kadane’s algorithm are the core patterns behind the majority of list-based interview questions.