CSV files store table-like data as plain text rows and columns.
Python has a csv module so you do not need to split lines manually.
Use CSV when exchanging simple spreadsheet data, exports, reports, logs, or bulk records.
A CSV reader parses records according to quoting and delimiter rules; it does more than split a line at each comma. A quoted field may contain a comma, a quote, or even a newline. Use csv.reader for positional rows and csv.DictReader when a header should name each field.
Open real files as text with an explicit encoding and newline="". The empty newline setting lets the csv module recognize embedded newlines and write platform-safe row endings itself. UTF-8 is a practical default when the producer and consumer agree on it; utf-8-sig can also consume a UTF-8 byte-order mark exported by some spreadsheet tools.
import csv
from io import StringIO
data = StringIO("name,score\nMaya,90\nRavi,82\n")
for row in csv.DictReader(data):
print(row["name"], int(row["score"]))
Maya 90
Ravi 82
DictReader uses the first row as field names.
csv.writer writes sequences, while csv.DictWriter maps named values into a declared column order. DictWriter requires fieldnames because dictionaries may contain fields that do not belong in the export. Its default extrasaction="raise" is useful: an unexpected key fails visibly instead of silently dropping data.
Write the header once for a new file, then pass rows to writerow or writerows. None is serialized as an empty field by the standard writer, so choose an explicit missing-value convention when an empty string and a missing value must remain distinct after a round trip.
import csv
from io import StringIO
output = StringIO()
writer = csv.DictWriter(output, fieldnames=["name", "passed"])
writer.writeheader()
writer.writerow({"name": "Maya", "passed": True})
print(output.getvalue())
name,passed
Maya,True
DictWriter writes the header and then a row matching those fields.
CSV is a family of tabular text formats, not one perfectly uniform format. A supplier may send semicolon-separated records, single-quoted fields, or a tab-separated export. Pass a known dialect or explicit formatting parameters when the data contract is documented. csv.Sniffer can suggest a delimiter from a representative sample, but detection is a heuristic and should not replace validation.
Quoting controls how delimiters and line breaks remain part of one field. QUOTE_MINIMAL quotes only fields that require it. QUOTE_ALL is predictable for strict downstream systems. QUOTE_NONNUMERIC also converts unquoted input fields to floats, which is rarely a complete business-data conversion strategy. Parse first, then apply field-specific types.
import csv
from io import StringIO
source = StringIO('product;price\n"Tea, green";4.50\n')
reader = csv.DictReader(source, delimiter=";")
row = next(reader)
print(row["product"])
print(float(row["price"]) * 2)
Tea, green
9.0
The comma belongs to the quoted product name; only semicolons separate columns. Price conversion happens after parsing.
Parsing proves that a row follows CSV syntax; it does not prove that the row is valid for the application. Validate the header, required fields, type conversions, ranges, and cross-field rules before mutating a database. Collect row-numbered errors when users should be able to correct a batch, or stop at the first error when partial acceptance is unsafe.
DictReader can expose irregular rows. Extra values are stored under restkey, and missing values use restval. Set explicit sentinels when these cases must be distinguished from a genuinely empty field. Normalize only what the contract permits: trimming an identifier may be safe, while changing capitalization in a case-sensitive code may corrupt it.
import csv
from io import StringIO
source = StringIO("name,score\nMaya,91\nRavi,high\n")
reader = csv.DictReader(source)
for row in reader:
try:
score = int(row["score"])
if not 0 <= score <= 100:
raise ValueError("score must be 0..100")
print(f"accepted: {row['name']}")
except (TypeError, ValueError) as error:
print(f"record {reader.line_num}: {error}")
accepted: Maya
record 3: invalid literal for int() with base 10: 'high'
The parser supplies text fields and the application applies the integer and range contract. line_num identifies the failing source record.
CSV is appropriate for flat records and interchange, but it has no native types, nested objects, constraints, relationships, or transaction model. Use JSON for nested exchange data and a database when records need durable querying, concurrent updates, or enforced integrity. Large files should be streamed row by row rather than loaded into one list.
A syntactically valid export can still be dangerous. Spreadsheet programs may interpret cells beginning with =, +, -, or @ as formulas. If untrusted text will be opened in a spreadsheet, apply the receiving organization's formula-injection policy and preserve the original value separately. Never assume quoting alone disables formula execution.
Try this next
0 of 3 completed
No. CSV is plain text table data. Excel files can contain formulas, sheets, styles, and richer workbook features.
Use CSV for flat rows and columns. Use JSON for nested objects, lists, and structured API-style data.
It lets the csv module handle row endings consistently, especially across operating systems.
Explore 500+ free tutorials across 20+ languages and frameworks.