I still remember the week I stopped tracking leave in a shared Excel file. I once helped a 10-person U.S. team whose HR tracker kept breaking, since someone overwrote someone else’s row or forgot to update a formula every month. So I built a tiny Python command-line app to log leave requests, backed by a local SQLite database on my own machine.
While building it, I kept running into one question: which leave request is the longest, or whose balance is highest? That question led me back to one function. This guide walks through how to find the maximum value in Python using max(), with the same leave-request app as our running example.
By the end, you will know how to use max() with numbers, strings, lists, dictionaries, and full database records. Let’s start with the basics.
What Is the max() Function in Python?
max() is a built-in function in Python, meaning you don’t need to import anything to use it. It looks at a group of values and returns the single largest one. No loops, no manual comparisons.
Here’s the simplest form:
print(max(12, 45, 7))Output:
45Python compares each number and hands back the biggest one, whether you’re comparing exam scores, prices, or days someone requested off.
Basic Syntax of max()
The max() function accepts values in two main ways:
max(iterable, *, key=None, default=None)
max(arg1, arg2, *args, key=None)An iterable is any object you can loop over, like a list, tuple, set, or dictionary. You can pass one iterable, or pass multiple separate values (positional arguments) directly. Note that default only works with the single-iterable form; it has no effect with separate positional arguments.
Both of these work:
scores = [88, 92, 79, 95, 67]
print(max(scores))
print(max(88, 92, 79, 95, 67))Output:
95
95I executed the above example code and added the screenshot below.

The first line passes a list as a single iterable. The second passes the same numbers as five separate arguments, and Python treats them identically.
Finding the Maximum Value in Python Using max() With Different Data Types
Let’s go through the common data types you’ll work with: numbers (days requested), strings (employee names), and full records pulled from a database.
Numbers
This is the most common use case: days off, ages, hours worked, prices, anything numeric.
days_requested = [4, 9, 1, 6, 3]
print(max(days_requested))Output:
9That line tells me someone requested 9 days off, the longest of the batch.
Strings
Python can also compare strings alphabetically, based on character codes, walking letter by letter to find the one that comes last.
employees = ["Emma", "Liam", "Noah", "Austin"]
print(max(employees))Output:
NoahI executed the above example code and added the screenshot below.

“Noah” comes after the other names alphabetically, so it wins. This is handy for finding the last name alphabetically, though it’s rarely why you’d reach for max() in a real app.
Lists, Tuples, and Sets
max() works the same way across a list (an ordered, changeable collection), a tuple (an ordered, unchangeable collection), and a set (an unordered collection with no duplicates). If you’re unsure how these three differ, it’s worth reading about how to compare lists, tuples, sets, and dictionaries in Python before going further.
leave_days_list = [4, 9, 1, 6, 3]
leave_days_tuple = (4, 9, 1, 6, 3)
leave_days_set = {4, 9, 1, 6, 3}
print(max(leave_days_list))
print(max(leave_days_tuple))
print(max(leave_days_set))Output:
9
9
9All three return the same answer, since max() doesn’t care about container type.
Using max() With Dictionaries in Python
Dictionaries trip up beginners because a dictionary stores key-value pairs, and max() needs to know which part you want.
Say I track total leave days per employee this year:
leave_balance = {"Emma": 5, "Liam": 12, "Austin": 3, "Denver": 8}
print(max(leave_balance))
print(max(leave_balance.values()))
print(max(leave_balance, key=leave_balance.get))Output:
Liam
12
LiamThe first call, max(leave_balance), loops over the dictionary’s keys by default, returning “Liam” simply because that name is alphabetically last — a coincidence, not the answer we wanted.
The second call, max(leave_balance.values()), looks only at the numbers and returns 12, the highest balance.
The third call is the one I actually use. The key parameter tells max() to use leave_balance.get to look up each key’s value before comparing, so it returns the key (“Liam”) tied to the highest balance. For a deeper look at this pattern, see this guide on finding the max value in a dictionary in Python.
The key Parameter: Comparing by a Specific Field
This is where max() becomes genuinely powerful, and it’s the part I use most in my leave app. The key parameter accepts a function. Instead of comparing raw items, max() runs each item through that function, compares the results, and returns the original item with the highest result.
Let’s say each leave request is stored as a dictionary with an employee name and number of days:
requests = [
{"employee": "Emma", "days": 5},
{"employee": "Liam", "days": 12},
{"employee": "Austin", "days": 3},
]
longest_request = max(requests, key=lambda r: r["days"])
print(longest_request)Output:
{'employee': 'Liam', 'days': 12}I executed the above example code and added the screenshot below.

I used a lambda, a small, unnamed function you define inline. Here, lambda r: r["days"] tells max() to look at the "days" field of each dictionary r when deciding which one is largest. If lambdas feel unfamiliar, this guide on how to use lambda functions in Python covers the basics.
You can also write this with a named function instead of a lambda:
def get_days(request):
return request["days"]
longest_request = max(requests, key=get_days)
print(longest_request)Output:
{'employee': 'Liam', 'days': 12}Same result. Lambdas are just a shortcut for short, one-time functions.
Getting the Field, Not the Whole Record
Sometimes I only want the employee’s name, not the whole dictionary:
longest_request = max(requests, key=lambda r: r["days"])
print(f"{longest_request['employee']} requested the most days: {longest_request['days']}")Output:
Liam requested the most days: 12This pattern — find the max record, then pull the field you need — comes up constantly with multi-attribute data.
Handling Ties and Empty Lists
Two edge cases catch beginners off guard: ties and empty data.
Ties
If two items tie for the maximum, max() returns only the first one it encounters.
tied_requests = [
{"employee": "Emma", "days": 10},
{"employee": "Liam", "days": 10},
]
result = max(tied_requests, key=lambda r: r["days"])
print(result)Output:
{'employee': 'Emma', 'days': 10}Emma appears first, so she’s returned, even though Liam requested an equal number of days. For every tied record, filter manually instead of relying on max() alone.
The default Parameter for Empty Iterables
Calling max() on an empty list without a fallback raises a ValueError, which matters since your leave-request list might be empty when the app first starts.
new_team_requests = []
print(max(new_team_requests, default=0))Output:
0The default parameter tells max() what to return instead of crashing, which I use whenever a new employee has no leave history yet.
Building the Leave Request App: Where max() Fits In
Let’s look at the app I built, since this is where these pieces come together. I kept it as a single file at first, leave_app.py, and only split it into modules (db.py, app.py, reports.py) once it grew past a few hundred lines. For a 10-person team, one file is enough.
Setting Up the Database
I used sqlite3, part of Python’s standard library, which stores an entire database in one local file with no server needed:
import sqlite3
conn = sqlite3.connect("leave_tracker.db")
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS leave_requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
employee_name TEXT NOT NULL,
start_date TEXT NOT NULL,
end_date TEXT NOT NULL,
days_requested INTEGER NOT NULL,
status TEXT DEFAULT 'pending'
)
""")
conn.commit()
print("Table ready.")Output:
Table ready.Each row holds one leave request: who asked, the dates, the day count, and its status.
Adding a Leave Request With User Input
Next, I needed a way to add requests from the terminal, using input() to collect the dates as text and datetime to calculate the duration.
from datetime import datetime
def add_leave_request(cursor, conn):
employee_name = input("Enter employee name: ")
start_date_str = input("Enter start date (YYYY-MM-DD): ")
end_date_str = input("Enter end date (YYYY-MM-DD): ")
start = datetime.strptime(start_date_str, "%Y-%m-%d")
end = datetime.strptime(end_date_str, "%Y-%m-%d")
days_requested = (end - start).days
cursor.execute(
"INSERT INTO leave_requests (employee_name, start_date, end_date, days_requested) VALUES (?, ?, ?, ?)",
(employee_name, start_date_str, end_date_str, days_requested)
)
conn.commit()
print(f"Added request for {employee_name}: {days_requested} days")Output (sample run):
Enter employee name: Emma Johnson
Enter start date (YYYY-MM-DD): 2026-08-03
Enter end date (YYYY-MM-DD): 2026-08-07
Added request for Emma Johnson: 4 daysI use strptime() to turn typed text into a real datetime object, since you can’t subtract plain strings but you can subtract datetime objects. end - start gives a timedelta, and .days pulls the whole number of days from it, since HR needs an actual day count, not two dates side by side. If your app takes dates from users, also check out how to validate that a string is a real date in Python, this guide on calculating days between two dates in Python, and this piece on how to ask for user input in Python.
Listing All Requests
def list_requests(cursor):
cursor.execute("SELECT employee_name, start_date, end_date, days_requested, status FROM leave_requests")
rows = cursor.fetchall()
for row in rows:
print(row)
return rowsOutput:
('Emma Johnson', '2026-08-03', '2026-08-07', 4, 'pending')
('Liam Carter', '2026-09-01', '2026-09-10', 9, 'pending')
('Austin Reed', '2026-08-15', '2026-08-16', 1, 'pending')Finding the Longest Leave Request With max()
Once I have all requests as rows, finding the longest one is a one-liner:
rows = [
("Emma Johnson", "2026-08-03", "2026-08-07", 4, "pending"),
("Liam Carter", "2026-09-01", "2026-09-10", 9, "pending"),
("Austin Reed", "2026-08-15", "2026-08-16", 1, "pending"),
]
longest = max(rows, key=lambda r: r[3])
print(f"Longest request: {longest[0]} for {longest[3]} days")Output:
Longest request: Liam Carter for 9 daysEach row is a tuple, so r[3] grabs the days_requested field (index 3) for comparison. This is the same key parameter pattern from earlier, applied to database rows. For named fields instead of index numbers, see this guide on how to sort a list of objects by attribute in Python.
Approving a Request
def approve_request(cursor, conn, request_id):
cursor.execute("UPDATE leave_requests SET status = 'approved' WHERE id = ?", (request_id,))
conn.commit()
print(f"Request {request_id} approved.")Output:
Request 2 approved.Finding the Maximum Value in Python Using max() in a Database Query
You can also let SQLite do the work with its own MAX() function:
cursor.execute("SELECT MAX(days_requested) FROM leave_requests")
result = cursor.fetchone()
print(result)Output:
(9,)MAX() alone only returns the number, not the matching employee, since SQL doesn’t automatically tie a row to that value. To get both together, sort the rows and grab the top one instead:
cursor.execute("SELECT employee_name, days_requested FROM leave_requests ORDER BY days_requested DESC LIMIT 1")
result = cursor.fetchone()
print(result)Output:
('Liam Carter', 9)This matches what max() found earlier. I still prefer pulling rows into Python with fetchall() and using max() with a key parameter, since it’s more predictable and easier to debug when you’re new to SQL.
Pro Tip: Whenever I’m not 100% sure my key function is pulling the right field, I print out
key=lambda r: r[3]results for a couple of test rows first. It takes ten seconds and has saved me from silently comparing the wrong column more than once.
Things to Keep in Mind
- max() needs comparable items. You can’t mix strings and numbers in the same call, like
max("Emma", 5), or Python raises a TypeError. - Ties return the first match only. If two employees request the same number of days, max() won’t tell you about the second one automatically.
- Empty data will crash your app without default=. Always add a fallback value when the leave list might be empty, especially for new hires.
- The key parameter compares computed values, not the raw items. Make sure your lambda or function actually returns the field you intend to compare.
- Database rows are tuples by index, not dictionaries. Double-check your index numbers (like
r[3]) match the column order in your CREATE TABLE statement. - max() finds one winner, not a ranked list. If you need the top five longest requests, consider sorting rather than using max().
Frequently Asked Questions
What is the difference between max() and sorted() in Python?
max() returns only the single largest item from a group, while sorted() rearranges every item from smallest to largest. If you only need the top value, max() is faster and clearer; for a ranked list of all leave requests, sorting is the better approach.
Can max() work with more than one condition?
Not directly, but you can combine conditions inside your key function. For example, key=lambda r: (r[“days”], r[“employee”]) compares primarily by days and uses the name to break ties, since Python compares tuples element by element.
Why does max() return the wrong answer on a dictionary?
This happens because max(my_dict) compares keys by default, not values. Use max(my_dict.values()) for the largest value, or max(my_dict, key=my_dict.get) for the key tied to it.
Does max() work on an empty list?
No, calling max() on an empty list raises a ValueError unless you supply a default= value. Always include a default when the data might be empty, such as a new employee with no leave history.
How do I find the maximum value in Python using max() for a specific dictionary field?
Pass a list of dictionaries into max() with a key function that returns the field you want, like key=lambda r: r["days"]. Python compares that field across all dictionaries and returns the whole dictionary with the highest value.
Can I use max() to compare dates instead of numbers?
Yes, as long as your dates are stored as datetime objects rather than plain text. Python compares them chronologically, so max() returns the latest date without extra conversion.
Finding the maximum value in Python using max() comes down to picking the right input: a plain iterable for simple values, or a key function when you’re comparing records by a specific field. Once you get comfortable with the key parameter and the default fallback, max() handles almost every “which one is biggest” question your app will ever ask. I hope you found this article helpful.
You May Also Like
- Find the Largest and Smallest Numbers in Python
- Find the Index of the Maximum Value in an Array Using Python
- Sort a List of Tuples by the Second Element in Python
- Python List Comprehension
- Python Dictionary Comprehension

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.