Python Β· Beginner Β· VINO PH Β· Interactive

VINO PH β€”
Interactive Python Wine Shop
Run Live in Your Browser

A complete Python wine ordering system that runs live in your browser. No installation needed. Click "Run Program" below to start the interactive experience.

Every line is explained step by step β€” from nested dictionaries to defensive input validation. Learn by doing.

πŸ“… July 16, 2026 ⏱ 20 min read πŸŽ“ Beginner 🐍 Python 3.12 ⚑ Live
Run Program Now View Source Abstraction Hub

VINO PH: A Python Learning Journey

🍷 Welcome to VINO PH

This page presents a complete, production-quality Python program for a Philippine wine shop ordering system called VINO PH. It demonstrates core Python concepts: nested dictionaries as a mini-database, f-strings with format specifiers for clean output, while True loops with try/except for robust input validation, arithmetic computation, and a senior citizen discount feature.

Every concept is introduced in the context of a real, working program β€” so you see why each design decision was made. By the end, you'll understand not just the code, but the thinking behind the code.

VINO PH is intentionally small enough to read in one sitting, yet it packs in almost every pattern a beginner will meet again and again in bigger, real-world systems: a data layer (the wines dictionary), a presentation layer (the formatted menu and receipt), a validation layer (the two while True loops), and a business-rules layer (the senior discount calculation). Professional applications β€” a point-of-sale system, an e-commerce checkout, a booking engine β€” are built from the exact same four layers, just at a much larger scale. Learning to recognize this shape in a 70-line script is what makes it possible to recognize it later inside a 70,000-line codebase.

15 wines in menu 7 core concepts 7 step-by-step explanations πŸ‡΅πŸ‡­ PHP pricing ⚑ Live interactive
🐍
Language
Python 3
πŸ“¦
Concepts
7 Core Topics
🍾
Wines
15 Selections
⚑
Mode
Interactive

Run VINO PH in Your Browser

Click "Run Program" to start the VINO PH wine shop. The program runs entirely in your browser using Pyodide β€” Python compiled to WebAssembly. Type your responses directly in the terminal. Senior citizens get a 10% discount!

VINO PH β€” Live Python Terminal
// Python interpreter loading... Click "Run Program" to start VINO PH
>>>

On a phone keyboard, tap Send (or the paper-plane button) if the Return/Go key doesn't submit your answer.

⚑ Runs entirely in browser 🐍 Python 3.12 (Pyodide) πŸ“¦ No installation needed πŸ‘΄ 10% Senior Discount

Complete Python Script

wine_shop.py
# ── VINO PH β€” Wine Shop (Philippines) ──
# Python 3 Β· Interactive Β· Poetic Bytes

wines = {
    1:  {"name": "Yellow Tail Cabernet Sauvignon (Australia)",          "price": 799},
    2:  {"name": "Jacob's Creek Shiraz (Australia)",                   "price": 899},
    3:  {"name": "Concha y Toro Frontera Cabernet Sauvignon (Chile)",   "price": 599},
    4:  {"name": "Beringer Founders' Estate Merlot (USA)",             "price": 1299},
    5:  {"name": "Robert Mondavi Private Selection Chardonnay (USA)",  "price": 1499},
    6:  {"name": "Gallo Family Vineyards Merlot (USA)",               "price": 649},
    7:  {"name": "Sutter Home Cabernet Sauvignon (USA)",              "price": 699},
    8:  {"name": "Lindemans Bin 65 Chardonnay (Australia)",           "price": 899},
    9:  {"name": "Penfolds Koonunga Hill Shiraz Cabernet (Australia)", "price": 1199},
    10: {"name": "Wolf Blass Yellow Label Cabernet Sauvignon",        "price": 1099},
    11: {"name": "Hardys Stamp Shiraz Cabernet (Australia)",          "price": 799},
    12: {"name": "Oxford Landing Cabernet Sauvignon (Australia)",     "price": 749},
    13: {"name": "Woodbridge by Robert Mondavi Cabernet (USA)",      "price": 999},
    14: {"name": "Kim Crawford Sauvignon Blanc (New Zealand)",       "price": 1699},
    15: {"name": "Oyster Bay Sauvignon Blanc (New Zealand)",         "price": 1499},
}

# ── Welcome banner ──
print("==================================================")
print("     WELCOME TO VINO PH - Wine Shop (Philippines)")
print("     Available Wines (Prices in PHP per bottle)")
print("==================================================")

# ── Display the menu via for loop ──
for num, wine in wines.items():
    print(f"{num:2d}. {wine['name']:50} β‚±{wine['price']:,.0f}")

# ── First input loop: wine selection ──
while True:
    try:
        choice = int(input("\nEnter the number of the wine you want to buy (1-15): "))
        if choice in wines:
            selected_wine = wines[choice]
            print(f"\nYou selected: {selected_wine['name']}")
            print(f"Price per bottle: β‚±{selected_wine['price']:,}")
            break
        else:
            print("Invalid number! Please choose between 1 and 15.")
    except ValueError:
        print("Please enter a valid number!")

# ── Second input loop: quantity ──
while True:
    try:
        quantity = int(input("\nEnter quantity (bottles): "))
        if quantity > 0:
            break
        else:
            print("Quantity must be at least 1!")
    except ValueError:
        print("Please enter a valid number!")

# ── Senior Citizen Discount ──
is_senior = input("\nAre you a senior citizen? (yes/no): ").strip().lower()
discount_rate = 0.10 if is_senior == "yes" else 0.00

# ── Computation ──
total_cost = selected_wine['price'] * quantity
discount_amount = total_cost * discount_rate
final_cost = total_cost - discount_amount

# ── Print receipt ──
print("\n" + "=" * 50)
print("           VINO PH - RECEIPT")
print("=" * 50)
print(f"Wine          : {selected_wine['name']}")
print(f"Price per bottle: β‚±{selected_wine['price']:,.0f}")
print(f"Quantity      : {quantity}")
print(f"Subtotal      : β‚±{total_cost:,.0f}")
if discount_amount > 0:
    print(f"Senior Discount (10%): -β‚±{discount_amount:,.0f}")
print(f"Total Cost    : β‚±{final_cost:,.0f}")
print("=" * 50)
print("Thank you for shopping at VINO PH! 🍷")

Step-by-Step Explanation

01

The Wine Inventory β€” Dictionary Data Structure

Data Structure β–Ύ
wines = {
    1: {"name": "Yellow Tail Cabernet Sauvignon", "price": 799},
    2: {"name": "Jacob's Creek Shiraz", "price": 899},
    ... (15 items total)
}
Why was this code used?
A dictionary (dict) is the ideal Python data structure when you need to look up values by a key. Here, each wine number (1–15) is a key, and each value is another dictionary containing the wine's name and price. This creates a nested dictionary β€” a dictionary inside a dictionary.
What is its significance?
It acts as the program's database β€” the single source of truth for all product information. Instead of scattering 15 wine names and prices across dozens of variables, everything is organized in one place.
How does it operate?
When the user types a number (e.g. 5), the program uses it as a key: wines[5] instantly returns {"name": "Robert Mondavi...", "price": 1499}. No looping required β€” dictionary lookup is O(1) β€” instant access.
How does this affect the program's output?
Every later line of output β€” the menu, the confirmation line, the receipt β€” reads directly from this dictionary. Change a price here and it ripples correctly through the whole program automatically, because nothing else hard-codes the numbers.
dict { } nested dict key-value pairs O(1) lookup
02

Welcome Banner β€” print() Statements

Output / UI β–Ύ
print("==================================================")
print("     WELCOME TO VINO PH - Wine Shop (Philippines)")
print("     Available Wines (Prices in PHP per bottle)")
print("==================================================")
Why was this code used?
print() is Python's built-in function for displaying text output to the terminal. Multiple calls construct a visual banner that greets the user and sets context.
What is its significance?
This is the program's user interface header. The rows of = signs create a visual border β€” a classic terminal UI technique.
How does this affect the program's output?
It is the very first thing the user sees. A clear banner signals "this program is organized and trustworthy" before a single wine is even listed β€” first impressions matter as much in a terminal as they do in a GUI.
print() string literals sequential execution
03

Displaying the Menu β€” for Loop with f-strings

Iteration / Formatting β–Ύ
for num, wine in wines.items():
    print(f"{num:2d}. {wine['name']:50} β‚±{wine['price']:,.0f}")
Why was this code used?
A for loop with .items() efficiently iterates over every wine in the dictionary without repeating code.
What is the significance of f-strings and format specs?
f-strings allow Python variables to be embedded directly inside a string using {} braces. Format specifiers control column widths and number display:

β€’ {num:2d} β€” integer, at least 2 characters wide
β€’ {wine['name']:50} β€” string padded to 50 characters
β€’ {wine['price']:,.0f} β€” float with commas, 0 decimal places
How does this affect the program's output?
Without the format specifiers, every row of the menu would have a different length and the prices would drift out of alignment. With them, every row lines up into neat, readable columns β€” the same principle used in receipts, invoices, and spreadsheets.
for loop .items() f-string format specifier :2d :50 :,.0f
04

Wine Selection Loop β€” while True + try/except

Input Validation β–Ύ
while True:
    try:
        choice = int(input("\nEnter the number of the wine (1-15): "))
        if choice in wines:
            selected_wine = wines[choice]
            break
        else:
            print("Invalid number! Please choose between 1 and 15.")
    except ValueError:
        print("Please enter a valid number!")
Why while True?
while True creates an infinite loop that runs until explicitly stopped with break. This pattern guarantees the program never proceeds with invalid input.
Why try / except ValueError?
input() always returns a string. Wrapping it in int() converts it to an integer β€” but if the user types "abc", int() raises a ValueError. The try/except block catches that crash and prints a friendly message instead.
How does this affect the program's output?
This is the difference between a program that survives a typo and one that crashes and loses the customer's order. Every downstream line β€” the receipt, the total β€” depends on selected_wine being valid, so this loop is the gatekeeper for everything that follows.
while True try / except ValueError int(input()) in operator
05

Quantity Input Loop β€” Positive Integer Validation

Input Validation β–Ύ
while True:
    try:
        quantity = int(input("\nEnter quantity (bottles): "))
        if quantity > 0:
            break
        else:
            print("Quantity must be at least 1!")
    except ValueError:
        print("Please enter a valid number!")
Why is this loop separate?
Each loop has a single responsibility β€” a core principle of clean code. The first loop handles which wine, this loop handles how many.
Why is the condition quantity > 0?
The > form reads more naturally as "Must be a positive number." It explicitly rejects zero, negative numbers, and text.
How does this affect the program's output?
A quantity of zero or a negative number would corrupt the math later β€” total_cost = price * quantity would print a nonsensical or negative subtotal. Rejecting bad quantities here keeps every number in the receipt trustworthy.
while True quantity > 0 break single responsibility
06

Senior Citizen Discount & Total Cost Computation

Calculation β–Ύ
is_senior = input("\nAre you a senior citizen? (yes/no): ").strip().lower()
discount_rate = 0.10 if is_senior == "yes" else 0.00
total_cost = selected_wine['price'] * quantity
discount_amount = total_cost * discount_rate
final_cost = total_cost - discount_amount
What's the significance of the conditional expression?
The conditional expression 0.10 if is_senior == "yes" else 0.00 sets the discount rate to 10% for seniors and 0% otherwise in one clear line.
How is the final cost computed?
Three steps: First, total_cost is the product of price and quantity. Second, discount_amount is the total multiplied by the rate. Third, final_cost subtracts the discount from the total.
Why .strip().lower() on the input?
.strip() removes accidental leading/trailing spaces and .lower() normalizes the answer, so "Yes", " YES ", and "yes" are all treated identically. Without it, a stray space or capital letter would silently deny a senior their discount.
conditional expression arithmetic * and - business logic string .strip() .lower()
07

Receipt Output β€” f-strings with Number Formatting

Final Output β–Ύ
print("\n" + "=" * 50)
print("           VINO PH - RECEIPT")
print("=" * 50)
print(f"Wine          : {selected_wine['name']}")
print(f"Price per bottle: β‚±{selected_wine['price']:,.0f}")
print(f"Quantity      : {quantity}")
print(f"Subtotal      : β‚±{total_cost:,.0f}")
if discount_amount > 0:
    print(f"Senior Discount (10%): -β‚±{discount_amount:,.0f}")
print(f"Total Cost    : β‚±{final_cost:,.0f}")
print("=" * 50)
print("Thank you for shopping at VINO PH! 🍷")
Why use f-strings again here?
The receipt must display dynamic values β€” the actual wine chosen, the real price, the user's quantity, and the computed total. The :, format spec adds thousands separators (e.g. 1699 β†’ 1,699) for currency readability.
What is the significance of the conditional discount line?
The if discount_amount > 0: check ensures the discount line only appears when a discount was actually applied.
How does this affect the program's output?
This is the payoff moment: every earlier line of code β€” the dictionary, the loops, the discount math β€” exists purely to produce these final, correctly formatted lines. A bug anywhere upstream shows up here as a wrong price, a missing discount, or a crash, which is why testing usually starts by reading the receipt backwards.
f-string :, comma separator β‚± Unicode symbol conditional output

Key Python Concepts Explained

Nested Dictionaries as Mini-Databases. In professional software, data is usually stored in a database. In a small Python program, a nested dictionary serves exactly the same purpose. The outer dictionary's keys (integers 1–15) act like row IDs. The inner dictionaries act like rows in a table, each containing a name column and a price column. This is the same mental model used in SQL, MongoDB, and most modern data systems.

The Defensive Input Pattern. The combination of while True + try/except + break is one of the most important patterns in Python programming. It is called defensive programming β€” you assume the user will make mistakes and design your code to handle them gracefully without crashing.

f-strings vs Older String Formatting. f-strings (introduced in Python 3.6) are now the preferred method because they are readable, concise, and support format specifiers directly inside the curly braces. VINO PH uses advanced format specs like :2d, :50, and :,.0f.

πŸ’‘ Pro Tip: Try extending this program: add a discount system (if quantity >= 5: discount = 0.10), a cart system that allows multiple purchases, or export the receipt to a .txt file using open("receipt.txt", "w").

Why Every Programmer Should Learn This

🎯 It's Not About Wine β€” It's About Reliable Software

VINO PH looks like a small toy program, but the seven patterns inside it are the same seven patterns that show up in payroll systems, hospital scheduling software, banking apps, and e-commerce checkouts. A nested dictionary today, a full SQL table tomorrow. A while True + try/except loop today, a production form-validation layer tomorrow. Programmers who skip learning these fundamentals "because the real work uses frameworks" often struggle later, because every framework is ultimately built on top of these exact primitives.

There is also a quieter, more important lesson here: defensive programming is a form of respect for the user. The two while True loops in VINO PH exist so that a customer who fat-fingers a "6" as an "e" never sees a crash, a stack trace, or a lost order. Learning to anticipate human error β€” rather than assuming perfect input β€” is what separates code that works in a demo from code that survives contact with real people.

Same shape as production systems Transfers to any language Builds debugging intuition Foundation for frameworks

πŸ€– VINO PH in the Era of AI

It is tempting to think that in the age of AI coding assistants, understanding a program like VINO PH line-by-line is optional β€” that you can simply ask an AI to "write me a wine shop program" and move on. The opposite is true. AI tools like Claude are extremely good at generating code such as this, but they cannot substitute for a human who can read, verify, and reason about the code that gets generated. When an AI-written program produces a wrong total, silently swallows an exception, or applies a discount to the wrong customer, someone still has to trace the bug back through the dictionary lookups, the loops, and the arithmetic β€” exactly the skill this walkthrough builds.

In practice, the programmers who benefit most from AI assistance are the ones who already understand fundamentals like these. They can spot when generated code has an off-by-one error in {num:2d}, notice when a try/except block is silently hiding a real bug, or recognize when a "senior discount" conditional expression has its logic backwards. Fluency in fundamentals is what turns an AI from an autocomplete tool into a genuine collaborator β€” you direct it, review it, and correct it, rather than trusting it blindly.

AI writes faster, humans verify Fundamentals catch AI mistakes Literacy > blind trust

Concepts Used at a Glance

Concept Python Syntax Purpose in This Program
Nested Dictionarywines = {1: {"name":..., "price":...}}Stores all 15 wines and their prices as a structured database
print()print("text")Displays banner, menu, confirmations, and receipt to the user
for loop + .items()for num, wine in wines.items():Iterates and prints all 15 wines without repeating code
f-string formattingf"{num:2d}. {name:50} β‚±{price:,.0f}"Formats menu and receipt output with aligned columns and commas
Infinite loopwhile True:Keeps asking for input until the user enters a valid response
Exception handlingtry: ... except ValueError:Prevents crashes when user types non-numeric input
Type conversionint(input(...))Converts the string returned by input() into a usable integer
Membership testif choice in wines:Validates that the user's number matches an actual wine key (1–15)
break statementbreakExits the while loop once valid input is confirmed
Conditional expression0.10 if is_senior == "yes" else 0.00Sets discount rate based on senior citizen status
Arithmetictotal_cost = price * quantityComputes the final purchase total after all inputs are gathered

Share This Guide

Follow Poetic Bytes

Stay connected for more Python tutorials, code walkthroughs, and tech content.

Subscribe to Poetic Bytes

Level up your Python knowledge.

In-depth Python tutorials, AI insights, and software engineering guides β€” delivered straight to your inbox. No spam, ever.

Weekly Python tutorials AI & ML deep-dives OOP series updates Free, cancel anytime

πŸ”’ Join 8,400+ developers. Your email is never shared or sold.

You've Mastered VINO PH

🏁 What You've Accomplished

Congratulations! You've now seen not just a working Python program, but the thinking process behind every design choice β€” from the nested dictionary as a mini-database, to the defensive input pattern, to the receipt formatting. You even ran it live in your browser!

This is what separates a programmer who copies code from a developer who understands it. Every concept in VINO PH β€” dictionaries, loops, exception handling, f-strings, arithmetic β€” appears in real-world Python projects every single day.

7 core concepts mastered 15 wines modeled Full defensive input pattern Senior citizen discount logic ⚑ Ran live in browser
Run It Again View Source Abstraction Hub