Python CSV Handling for Absolute Beginners: A Complete Terminal Tutorial with csv.reader and csv.DictReader

Master Python CSV file operations from scratch with hands-on terminal demonstrations. Learn to read CSV files, handle headers, and work with both list and dictionary formats. Includes practical examples and troubleshooting.

23 min read

CSV (Comma-Separated Values) files are one of the most common ways to store and exchange data. In this comprehensive tutorial, we'll explore Python's built-in CSV handling capabilities through hands-on terminal examples, covering everything from basic file reading to advanced dictionary-based processing.

💡

đŸŽ¯ What You'll Learn: In this practical tutorial, you'll discover:

  • Understanding CSV file structure and format
  • Creating and examining sample CSV data
  • Using Python's csv.reader for basic CSV parsing
  • Working with csv.DictReader for structured data access
  • Handling CSV headers properly
  • Converting CSV data to Python lists and dictionaries
  • Reading and analyzing real employee data
  • Best practices for CSV file processing
  • Common troubleshooting scenarios

🚀 Getting Started with CSV Files

Let's begin our CSV journey by understanding what we're working with and setting up our development environment.

Prerequisites

Before we dive in, make sure you have:

  • Python 3.x installed on your system
  • Basic understanding of Python lists and dictionaries
  • Terminal/command line access
  • Text editor (nano, vim, or any editor)
  • Understanding of basic file operations

Setting Up Our Workspace

Let's start by checking our current directory and see what files we have:

ls

Terminal Output:

sample_data.csv

Perfect! We already have a CSV file to work with. This is a common scenario - you often receive CSV files from databases, spreadsheets, or APIs that you need to process with Python.

📊 Understanding CSV File Structure

Before diving into Python code, let's examine our CSV file to understand its structure:

cat sample_data.csv

Terminal Output:

name,age,city,salary,department,join_date
John Smith,28,New York,75000,Engineering,2022-01-15
Sarah Johnson,34,Los Angeles,82000,Marketing,2021-06-20
Mike Brown,42,Chicago,95000,Engineering,2020-03-10
Emily Davis,29,Houston,68000,Sales,2022-09-05
David Wilson,37,Phoenix,71000,HR,2021-11-12
Lisa Garcia,31,Philadelphia,78000,Marketing,2022-02-28
James Miller,45,San Antonio,102000,Engineering,2019-08-14
Maria Rodriguez,26,San Diego,63000,Sales,2023-01-20
Robert Taylor,39,Dallas,89000,Finance,2020-12-03
Jennifer Anderson,33,San Jose,76000,HR,2021-04-18
Christopher Lee,30,Austin,72000,Engineering,2022-07-25
Jessica White,27,Jacksonville,65000,Marketing,2023-03-08
Matthew Harris,41,San Francisco,98000,Finance,2020-05-16
Amanda Clark,35,Columbus,81000,Sales,2021-08-30
Daniel Lewis,32,Fort Worth,74000,HR,2022-04-12

CSV Structure Analysis

ComponentDescriptionExample
Header RowFirst line with column namesname,age,city,salary,department,join_date
Data RowsEach line represents one recordJohn Smith,28,New York,75000,Engineering,2022-01-15
SeparatorComma separates each field, (comma)
FieldsIndividual data valuesJohn Smith, 28, New York, etc.

This is employee data with 6 fields per record:

  1. name: Employee full name
  2. age: Employee age (number)
  3. city: Employee location
  4. salary: Annual salary (number)
  5. department: Work department
  6. join_date: Date when employee joined

🔨 Creating Our First CSV Reader Script

Now let's create a Python script to read this CSV file. We'll use a text editor to write our code:

nano csv-practice.py

Command Explanation:

  • nano is a simple text editor in the terminal
  • csv-practice.py is the filename we're creating
  • This opens the editor where we can write Python code

After creating the file, let's see what we wrote:

cat csv-practice.py

Terminal Output:

import csv

file_path = 'sample_data.csv'

with open(file_path, mode='r') as file:
	csv_reader = csv.reader(file)
	for row in csv_reader:
		print(row)

Code Breakdown

LineCodePurpose
1import csvImport Python's built-in CSV module
3file_path = 'sample_data.csv'Store the filename in a variable
5with open(file_path, mode='r') as file:Open file for reading (mode='r')
6csv_reader = csv.reader(file)Create CSV reader object
7-8for row in csv_reader: print(row)Loop through each row and print it

Key Concepts Explained

The with Statement:

  • Automatically opens and closes the file
  • Ensures file is properly closed even if an error occurs
  • Best practice for file handling in Python

File Mode 'r':

  • 'r' stands for "read mode"
  • File is opened for reading only
  • File must exist or you'll get an error

csv.reader():

  • Takes a file object as input
  • Returns a reader object that can be iterated
  • Automatically handles comma separation and parsing

đŸƒâ€â™‚ī¸ Running Our First CSV Script

Let's execute our script and see what happens:

python csv-practice.py

Terminal Output:

['name', 'age', 'city', 'salary', 'department', 'join_date']
['John Smith', '28', 'New York', '75000', 'Engineering', '2022-01-15']
['Sarah Johnson', '34', 'Los Angeles', '82000', 'Marketing', '2021-06-20']
['Mike Brown', '42', 'Chicago', '95000', 'Engineering', '2020-03-10']
['Emily Davis', '29', 'Houston', '68000', 'Sales', '2022-09-05']
['David Wilson', '37', 'Phoenix', '71000', 'HR', '2021-11-12']
['Lisa Garcia', '31', 'Philadelphia', '78000', 'Marketing', '2022-02-28']
['James Miller', '45', 'San Antonio', '102000', 'Engineering', '2019-08-14']
['Maria Rodriguez', '26', 'San Diego', '63000', 'Sales', '2023-01-20']
['Robert Taylor', '39', 'Dallas', '89000', 'Finance', '2020-12-03']
['Jennifer Anderson', '33', 'San Jose', '76000', 'HR', '2021-04-18']
['Christopher Lee', '30', 'Austin', '72000', 'Engineering', '2022-07-25']
['Jessica White', '27', 'Jacksonville', '65000', 'Marketing', '2023-03-08']
['Matthew Harris', '41', 'San Francisco', '98000', 'Finance', '2020-05-16']
['Amanda Clark', '35', 'Columbus', '81000', 'Sales', '2021-08-30']
['Daniel Lewis', '32', 'Fort Worth', '74000', 'HR', '2022-04-12']

Output Analysis

Why Lists? Each row is displayed as a Python list because:

CSV InputPython OutputExplanation
John Smith,28,New York['John Smith', '28', 'New York']CSV commas become list separators
Text and numbersAll stringsCSV values are always read as strings
Header rowFirst list itemHeader is treated like any other row

Important Observations:

  • All data is strings: Even numbers like '28' and '75000' are strings
  • Header included: The first row contains column names, not data
  • List format: Each row becomes a Python list with elements accessible by index
  • Brackets and quotes: Python list notation with single quotes around strings
💡

â„šī¸ String vs Number: CSV files store everything as text. Python reads all values as strings, so '28' is a string, not the number 28. You'll need to convert to integers or floats if you want to do math.

đŸŽ¯ Handling Headers Properly

The current output includes the header row with our data, which isn't ideal for data processing. Let's modify our script to handle headers separately:

nano csv-practice.py

Let's see the updated version:

cat csv-practice.py

Terminal Output:

import csv

file_path = 'sample_data.csv'

with open(file_path, mode='r') as file:
	csv_reader = csv.reader(file)
	header = next(csv_reader)
	for row in csv_reader:
		print(row)

New Code Addition

LineCodePurpose
7header = next(csv_reader)Read first row separately
8-9for row in csv_reader: print(row)Process remaining data rows

The next() Function:

  • next(csv_reader) reads and returns the next row from the CSV reader
  • After calling next(), the reader advances to the subsequent row
  • This effectively "skips" the header row for our data processing loop
  • The header is stored in the header variable for potential later use

Running the Updated Script

python csv-practice.py

Terminal Output:

['John Smith', '28', 'New York', '75000', 'Engineering', '2022-01-15']
['Sarah Johnson', '34', 'Los Angeles', '82000', 'Marketing', '2021-06-20']
['Mike Brown', '42', 'Chicago', '95000', 'Engineering', '2020-03-10']
['Emily Davis', '29', 'Houston', '68000', 'Sales', '2022-09-05']
['David Wilson', '37', 'Phoenix', '71000', 'HR', '2021-11-12']
['Lisa Garcia', '31', 'Philadelphia', '78000', 'Marketing', '2022-02-28']
['James Miller', '45', 'San Antonio', '102000', 'Engineering', '2019-08-14']
['Maria Rodriguez', '26', 'San Diego', '63000', 'Sales', '2023-01-20']
['Robert Taylor', '39', 'Dallas', '89000', 'Finance', '2020-12-03']
['Jennifer Anderson', '33', 'San Jose', '76000', 'HR', '2021-04-18']
['Christopher Lee', '30', 'Austin', '72000', 'Engineering', '2022-07-25']
['Jessica White', '27', 'Jacksonville', '65000', 'Marketing', '2023-03-08']
['Matthew Harris', '41', 'San Francisco', '98000', 'Finance', '2020-05-16']
['Amanda Clark', '35', 'Columbus', '81000', 'Sales', '2021-08-30']
['Daniel Lewis', '32', 'Fort Worth', '74000', 'HR', '2022-04-12']

Improvement Achieved:

  • ✅ No header row in the output
  • ✅ Only actual employee data is displayed
  • ✅ Header is preserved in the header variable for reference
  • ✅ Clean data processing without column names mixed in

đŸ—‚ī¸ Using csv.DictReader for Structured Data

While csv.reader gives us lists, csv.DictReader provides a more structured approach by creating dictionaries where keys are column names. Let's update our script:

nano csv-practice.py

Now let's see our enhanced version:

cat csv-practice.py

Terminal Output:

import csv

file_path = 'sample_data.csv'

data_list = []

with open(file_path, mode='r') as file:
	csv_reader = csv.DictReader(file)
	for row in csv_reader:
		data_list.append(row)

for item in data_list:
	print(item)

DictReader Code Analysis

ComponentCodePurpose
Storage Listdata_list = []Empty list to store all employee records
DictReadercsv.DictReader(file)Creates dictionary reader object
Data Collectiondata_list.append(row)Add each dictionary to our list
Display Loopfor item in data_list: print(item)Print each dictionary

Key Differences from csv.reader:

Featurecsv.readercsv.DictReader
Output TypeListsDictionaries
Header HandlingManual with next()Automatic
Data AccessBy index: row[0], row[1]By name: row['name'], row['age']
Ease of UseMore manual workMore intuitive

Running the DictReader Script

python csv-practice.py

Terminal Output:

{'name': 'John Smith', 'age': '28', 'city': 'New York', 'salary': '75000', 'department': 'Engineering', 'join_date': '2022-01-15'}
{'name': 'Sarah Johnson', 'age': '34', 'city': 'Los Angeles', 'salary': '82000', 'department': 'Marketing', 'join_date': '2021-06-20'}
{'name': 'Mike Brown', 'age': '42', 'city': 'Chicago', 'salary': '95000', 'department': 'Engineering', 'join_date': '2020-03-10'}
{'name': 'Emily Davis', 'age': '29', 'city': 'Houston', 'salary': '68000', 'department': 'Sales', 'join_date': '2022-09-05'}
{'name': 'David Wilson', 'age': '37', 'city': 'Phoenix', 'salary': '71000', 'department': 'HR', 'join_date': '2021-11-12'}
{'name': 'Lisa Garcia', 'age': '31', 'city': 'Philadelphia', 'salary': '78000', 'department': 'Marketing', 'join_date': '2022-02-28'}
{'name': 'James Miller', 'age': '45', 'city': 'San Antonio', 'salary': '102000', 'department': 'Engineering', 'join_date': '2019-08-14'}
{'name': 'Maria Rodriguez', 'age': '26', 'city': 'San Diego', 'salary': '63000', 'department': 'Sales', 'join_date': '2023-01-20'}
{'name': 'Robert Taylor', 'age': '39', 'city': 'Dallas', 'salary': '89000', 'department': 'Finance', 'join_date': '2020-12-03'}
{'name': 'Jennifer Anderson', 'age': '33', 'city': 'San Jose', 'salary': '76000', 'department': 'HR', 'join_date': '2021-04-18'}
{'name': 'Christopher Lee', 'age': '30', 'city': 'Austin', 'salary': '72000', 'department': 'Engineering', 'join_date': '2022-07-25'}
{'name': 'Jessica White', 'age': '27', 'city': 'Jacksonville', 'salary': '65000', 'department': 'Marketing', 'join_date': '2023-03-08'}
{'name': 'Matthew Harris', 'age': '41', 'city': 'San Francisco', 'salary': '98000', 'department': 'Finance', 'join_date': '2020-05-16'}
{'name': 'Amanda Clark', 'age': '35', 'city': 'Columbus', 'salary': '81000', 'department': 'Sales', 'join_date': '2021-08-30'}
{'name': 'Daniel Lewis', 'age': '32', 'city': 'Fort Worth', 'salary': '74000', 'department': 'HR', 'join_date': '2022-04-12'}

DictReader Output Analysis

Dictionary Structure: Each employee record is now a Python dictionary with:

KeyValue ExampleData TypeDescription
'name''John Smith'StringEmployee full name
'age''28'StringAge (as text, not number)
'city''New York'StringEmployee location
'salary''75000'StringSalary (as text, not number)
'department''Engineering'StringWork department
'join_date''2022-01-15'StringDate joined (YYYY-MM-DD format)
✅

✅ DictReader Advantages: With dictionaries, you can access data by column name (row['salary']) instead of remembering index positions (row[3]). This makes code more readable and less error-prone.

đŸŽ¯ Practical Data Access Examples

Let's explore how to access specific data from our CSV using both methods:

Accessing Data with csv.reader (Lists)

# If using csv.reader, data access is by index:
row = ['John Smith', '28', 'New York', '75000', 'Engineering', '2022-01-15']

name = row[0]        # 'John Smith'
age = row[1]         # '28'
city = row[2]        # 'New York'
salary = row[3]      # '75000'
department = row[4]  # 'Engineering'
join_date = row[5]   # '2022-01-15'

Accessing Data with csv.DictReader (Dictionaries)

# If using csv.DictReader, data access is by key:
row = {'name': 'John Smith', 'age': '28', 'city': 'New York', 'salary': '75000', 'department': 'Engineering', 'join_date': '2022-01-15'}

name = row['name']           # 'John Smith'
age = row['age']             # '28'
city = row['city']           # 'New York'
salary = row['salary']       # '75000'
department = row['department']   # 'Engineering'
join_date = row['join_date']     # '2022-01-15'

Why DictReader is Often Better:

Scenariocsv.reader ProblemDictReader Solution
Column AddedAll index numbers shiftKey names stay the same
Column ReorderedWrong data accessedCorrect data always accessed
Code ReadabilityMust remember what row[3] meansrow['salary'] is self-documenting

📊 Summary of CSV Methods

MethodBest ForProsCons
csv.readerSimple parsing, when you need listsFast, minimal memoryIndex-based access, manual header handling
csv.DictReaderStructured data, readable codeNamed access, automatic headersSlightly more memory usage

🚨 Common Issues and Troubleshooting

Issue 1: File Not Found Error

Problem: FileNotFoundError: [Errno 2] No such file or directory: 'sample_data.csv'

Causes and Solutions:

CauseCheck CommandSolution
Wrong directorylsNavigate to correct directory
Typo in filenamels *.csvCheck exact filename and spelling
File doesn't existls -laCreate or download the file

Issue 2: Empty or Malformed CSV

Problem: Script runs but no data appears or errors occur

Solutions:

# Check file contents
cat your_file.csv

# Check file size
ls -lh your_file.csv

# Count lines in file
wc -l your_file.csv

Issue 3: Encoding Issues

Problem: Strange characters appear in the output

Solution: Specify encoding when opening the file:

with open(file_path, mode='r', encoding='utf-8') as file:
    csv_reader = csv.DictReader(file)

📋 Python CSV Quick Reference Cheat Sheet

🚀 Essential Imports and Setup

import csv

# Basic file opening pattern
with open('filename.csv', mode='r') as file:
    # CSV operations here
    pass

📊 CSV Reading Methods Comparison

MethodOutput TypeCode ExampleBest For
csv.readerListscsv_reader = csv.reader(file)Simple parsing, minimal memory
csv.DictReaderDictionariescsv_reader = csv.DictReader(file)Structured data, named access

🔧 Complete Code Templates

Template 1: Basic csv.reader with Header Handling

import csv

file_path = 'your_file.csv'

with open(file_path, mode='r') as file:
    csv_reader = csv.reader(file)
    header = next(csv_reader)  # Skip header row

    for row in csv_reader:
        # row is a list: ['value1', 'value2', 'value3']
        print(row)
        # Access by index: row[0], row[1], row[2]

Template 2: csv.DictReader for Structured Data

import csv

file_path = 'your_file.csv'
data_list = []

with open(file_path, mode='r') as file:
    csv_reader = csv.DictReader(file)

    for row in csv_reader:
        # row is a dict: {'col1': 'value1', 'col2': 'value2'}
        data_list.append(row)
        # Access by name: row['column_name']

# Process collected data
for item in data_list:
    print(item['column_name'])

Template 3: Data Processing with Type Conversion

import csv

file_path = 'employee_data.csv'

with open(file_path, mode='r') as file:
    csv_reader = csv.DictReader(file)

    for row in csv_reader:
        # Convert strings to appropriate types
        name = row['name']                    # Keep as string
        age = int(row['age'])                 # Convert to integer
        salary = float(row['salary'])         # Convert to float

        print(f"{name} is {age} years old, salary: ${salary:,.2f}")

📖 Data Access Patterns

Taskcsv.reader (List)csv.DictReader (Dict)
Access first columnrow[0]row['column_name']
Get all valuesfor value in row:for value in row.values():
Get all keys/headersheader = next(csv_reader)row.keys()
Check if column existsif len(row) > index:if 'column' in row:

🔄 Common Data Processing Patterns

# Filter records based on condition
engineering_employees = []
for row in csv_reader:
    if row['department'] == 'Engineering':
        engineering_employees.append(row)

# Calculate statistics
salaries = [float(row['salary']) for row in data_list]
average_salary = sum(salaries) / len(salaries)
max_salary = max(salaries)
min_salary = min(salaries)

# Group by department
from collections import defaultdict
by_department = defaultdict(list)
for row in data_list:
    by_department[row['department']].append(row)

# Sort by column
sorted_by_age = sorted(data_list, key=lambda x: int(x['age']))
sorted_by_salary = sorted(data_list, key=lambda x: float(x['salary']), reverse=True)

🚨 Error Handling Template

import csv

def read_csv_safely(file_path):
    try:
        with open(file_path, mode='r', encoding='utf-8') as file:
            csv_reader = csv.DictReader(file)
            data = []

            for row_num, row in enumerate(csv_reader, start=2):  # Start at 2 (after header)
                try:
                    # Process row with validation
                    if not row['name'].strip():
                        print(f"Warning: Empty name in row {row_num}")
                        continue

                    data.append(row)

                except KeyError as e:
                    print(f"Missing column {e} in row {row_num}")
                except ValueError as e:
                    print(f"Invalid data in row {row_num}: {e}")

            return data

    except FileNotFoundError:
        print(f"Error: File '{file_path}' not found")
        return []
    except PermissionError:
        print(f"Error: Permission denied accessing '{file_path}'")
        return []
    except Exception as e:
        print(f"Unexpected error: {e}")
        return []

đŸŽ¯ Terminal Commands Quick Reference

CommandPurposeExample
lsList files in directoryls *.csv
cat filename.csvView CSV file contentscat sample_data.csv
head -n 5 file.csvView first 5 lineshead -n 3 data.csv
wc -l file.csvCount lines in filewc -l employees.csv
python script.pyRun Python scriptpython csv-practice.py

🔍 Debugging Checklist

IssueQuick FixPrevention
File not foundCheck ls and file pathUse absolute paths or verify working directory
Empty outputCheck if file has data with catValidate CSV structure first
Wrong data typesUse int() or float()Remember CSV data is always strings
KeyError with DictReaderCheck column names with row.keys()Verify header row spelling and spacing
Strange charactersAdd encoding='utf-8'Always specify encoding for text files

đŸŽ¯ Key Takeaways

✅ Remember These Points

  1. CSV Module: Always import the csv module for proper CSV handling
  2. File Handling: Use with open() to automatically manage file opening/closing
  3. String Data: All CSV data is read as strings, convert to numbers if needed
  4. csv.reader vs DictReader: Choose based on whether you want lists or dictionaries
  5. Header Handling: DictReader automatically handles headers, csv.reader requires manual handling
  6. Data Access: DictReader allows access by column name, more readable and maintainable
  7. File Path: Always verify file exists and path is correct before running script
✅

🎉 Congratulations! You've mastered Python CSV handling fundamentals including both csv.reader and csv.DictReader approaches. You can now read, process, and analyze CSV data efficiently, and you understand the trade-offs between different CSV processing methods.

What did you think of this guide? Try implementing your own CSV processing script with the sample data, or bring your own CSV files to practice with!


This tutorial walked through every command and concept step-by-step, explaining both the Python code and terminal operations. All examples were based on real terminal sessions to provide authentic learning experiences for absolute beginners.

Owais

Written by Owais

I'm an AIOps Engineer with a passion for AI, Operating Systems, Cloud, and Security—sharing insights that matter in today's tech world.

I completed the UK's Eduqual Level 6 Diploma in AIOps from Al Nafi International College, a globally recognized program that's changing careers worldwide. This diploma is:

  • ✅ Available online in 17+ languages
  • ✅ Includes free student visa guidance for Master's programs in Computer Science fields across the UK, USA, Canada, and more
  • ✅ Comes with job placement support and a 90-day success plan once you land a role
  • ✅ Offers a 1-year internship experience letter while you study—all with no hidden costs

It's not just a diploma—it's a career accelerator.

👉 Start your journey today with a 7-day free trial

Related Articles

Continue exploring with these handpicked articles that complement what you just read

More Reading

One more article you might find interesting