Bill splitter for friends
A group eats out, one person pays, and then the sums begin. This project builds a small tool for that, in three stages: an equal split, a split by what each person ordered, and a list of who should pay whom. It uses numbers, dictionaries, functions and formatting.
Stage 1: equal split
def split_equally(amount, people, tip_percent=0):
total = amount + amount * tip_percent / 100
return round(total / people, 2)
print(split_equally(1840, 4))
print(split_equally(1840, 4, tip_percent=10))Output
460.0
506.0Rounding to two places keeps the answer in rupees and paise. Because of rounding, the shares may add up to a paisa or two more or less than the bill. The next block shows how to check.
share = round(1000 / 3, 2)
print(share, share * 3)Output
333.33 999.99A real app gives the leftover paisa to one person. For friends, rounding each share up to the next rupee is simpler.
import math
print(math.ceil(1000 / 3))Output
334Stage 2: each pays for their own order
Now store what each person ordered. A dictionary maps a name to a list of prices.
orders = {
"Asha": [220, 60],
"Ravi": [340],
"Meena": [180, 60, 90],
}
for name, items in orders.items():
print(f"{name:<6}{sum(items):>6}")
print("Food total:", sum(sum(items) for items in orders.values()))Output
Asha 280
Ravi 340
Meena 330
Food total: 950Tax and service charge are usually a percentage of the food, so each person should carry them in proportion to what they ate. Work out one multiplier and apply it to everyone.
def shares(orders, extra_percent):
factor = 1 + extra_percent / 100
return {name: round(sum(items) * factor, 2) for name, items in orders.items()}
orders = {"Asha": [220, 60], "Ravi": [340], "Meena": [180, 60, 90]}
result = shares(orders, extra_percent=5)
for name, amount in result.items():
print(f"{name:<6}{amount:>8.2f}")
print(f"{'Total':<6}{sum(result.values()):>8.2f}")Output
Asha 294.00
Ravi 357.00
Meena 346.50
Total 997.50The function body is a dictionary comprehension from lesson 20. It builds a new dictionary with the same names and the adjusted amounts.
Shared dishes
Some dishes are shared by the whole table. Split those equally and add them to each person's own items.
def shares(orders, shared, extra_percent):
factor = 1 + extra_percent / 100
each = sum(shared) / len(orders)
return {name: round((sum(items) + each) * factor, 2) for name, items in orders.items()}
orders = {"Asha": [220], "Ravi": [340], "Meena": [180, 90]}
result = shares(orders, shared=[450, 120], extra_percent=5)
print(result)Output
{'Asha': 430.5, 'Ravi': 556.5, 'Meena': 483.0}Stage 3: who owes whom
Suppose different people paid for different things during a trip. First find each person's balance: what they paid minus the fair share. A positive balance means the group owes them money.
paid = {"Asha": 2400, "Ravi": 0, "Meena": 600}
fair = sum(paid.values()) / len(paid)
balance = {name: amount - fair for name, amount in paid.items()}
print(fair)
print(balance)Output
1000.0
{'Asha': 1400.0, 'Ravi': -1000.0, 'Meena': -400.0}Then settle. Take the person who owes the most and the person who is owed the most, move as much as possible between them, and repeat until everyone is at zero.
def settle(paid):
fair = sum(paid.values()) / len(paid)
balance = {name: round(amount - fair, 2) for name, amount in paid.items()}
payments = []
while True:
debtor = min(balance, key=balance.get)
creditor = max(balance, key=balance.get)
amount = round(min(-balance[debtor], balance[creditor]), 2)
if amount < 0.01:
break
payments.append(f"{debtor} pays {creditor} Rs {amount:.2f}")
balance[debtor] += amount
balance[creditor] -= amount
return payments
for line in settle({"Asha": 2400, "Ravi": 0, "Meena": 600, "Kabir": 1000}):
print(line)Output
Ravi pays Asha Rs 1000.00
Meena pays Asha Rs 400.00This loop always ends, because every round brings at least one person's balance to zero.
Things to notice
- Money is stored as plain numbers and formatted only when printed.
- Each stage is a function that takes data and returns data, so it can be tested without typing anything.
- Floats can be off by a tiny fraction, which is why the loop stops at "less than one paisa" instead of "exactly zero". Programs that handle real money store whole paise as integers, or use Python's
decimalmodule.
Ideas to extend it
- Ask for names and amounts with
inputuntil the user types an empty line. - Save the trip to a file and load it next time.
- Print a message for each person, ready to paste into a group chat.
Exercise 1. Write split_with_cap(amount, people) that rounds each share up to the next 10 rupees. Test it with 1840 and 3 people.
Show one answer
import math
def split_with_cap(amount, people):
return math.ceil(amount / people / 10) * 10
print(split_with_cap(1840, 3))Output
620Examples on this page were run with Python 3.14 on 12 November 2026. The output shown is the real output.
This is an independent learning site. It is not connected with or approved by the Python Software Foundation. "Python" is a trademark of the Python Software Foundation and is used here only to name the language.