DEV Community

Om Kolhapure
Om Kolhapure

Posted on

Week 2: From Sphaghetti to Functions

Week 1 was about getting things to work.

Week 2 was about getting things to work properly.

The difference is bigger than I expected. I spent six days going back to code I was already proud of and realising it could be cleaner, safer, and smarter. Functions, error handling, built-in modules, file I/O — this week the pieces stopped feeling like separate topics and started feeling like a toolkit.

Here's what happened.


Day 8 — Functions: One Job, One Function

The rule I was given for Day 8: every function does ONE thing.

That sounds obvious until you look at your old code and realise every function you wrote does about four things. I went back to the adventure game from Week 1 and refactored it properly — breaking out start_game(), print_story(), print_location(), move_player(), beast(), check_up(), pick_up(), and game_end() into eight focused functions.

But the real lesson hit me when I built the tip calculator from scratch with clean separation from the start:

def main():
    #Ask user to input bill, tip, people
    bill = input("Enter total bill: ").strip()
    tip = input("How much tip would you like to give?: ").strip()
    people = input("Enter number of people: ").strip()
    per_person = calculate(bill, tip, people)
    print(f"Each person must cobntribute {per_person}$.")

def calculate(bill, tip, people):
    #Convert from str to int and calculate the split
    if "$" in bill:
        bill = bill.removesuffix("$")
    bill = float(bill)
    if "%" in tip:
        tip = tip.removesuffix("%")
    tip = int(tip) / 100
    people = int(people)
    return round((bill + (bill * tip)) / people, 2)

main()
Enter fullscreen mode Exit fullscreen mode

main() talks to the user. calculate() does the math. Neither steps on the other's toes.

Two things I didn't expect to love here: removesuffix() — so you can type "$42" or just "42" and it handles both — and how clean return makes functions feel. You hand it data, it hands you an answer. No side effects, no surprises.


Day 9 — Parameters & Return Values

Day 9 was about really understanding what flows into and out of functions. The tip calculator covered this well — calculate() takes three parameters, does one job, and returns one value.

What clicked: functions are just machines. You feed them inputs, they produce an output. Once I started thinking that way, writing them felt much more intentional. Every parameter has a purpose. Every return value means something.

I spent extra time making calculate() handle edge cases:

  • What if someone types $42 with a dollar sign? → removesuffix("$") strips it
  • What if they type 15% instead of 15? → removesuffix("%") strips that too
  • Division by zero for people? → int(people) would be 0 and the function would crash — something I noted to fix with error handling later

This kind of thinking — what could go wrong? — is new for me. Week 1 me just hoped the user typed the right thing.


Day 10 — Scope & Modules

Day 10 was scope — understanding what variables live where — and modules, which is how Python lets you split code across files.

The adventure game got its cleanest version yet. Better input validation was added so the game no longer silently accepts invalid room names:

def move_player():
    global player_location
    while True:
        go = input("\nWhere would you like to go?\nbedroom\nkitchen\nliving room\n\n ")
        if go not in locations:
            print("Invalid location please choose from the list")
        if player_location == go:
            print(f"Already in {player_location}")
        else:
            player_location = go
            print_location()
            beast()
            if not game_state:
                break
            check_up()
            break
Enter fullscreen mode Exit fullscreen mode

The retry logic in beast() also got cleaner:

def beast():
    global player_location
    global game_state
    beast_location = random.choice(locations)
    if beast_location == player_location:
        print("you are Dead")
        retry_input = input("Would you like to play again?(yes/no) ")
        if retry_input != "yes":
            game_state = False
        player_location = "bedroom"
    else:
        print("growlssss.........The beast is nearby")
Enter fullscreen mode Exit fullscreen mode

The big scope lesson: global variables are a trade-off. They're convenient for a small game, but they make bigger programs hard to reason about. I'm already starting to see why Week 3 will probably involve classes.


Day 11 — Error Handling: try/except

This was one of my favourite days. Before try/except, my programs crashed the moment a user did something unexpected. After it, they handle the unexpected and keep running.

I built a days-until calculator — it tells you how many days until any date you enter:

from datetime import date
#Take input from user for target
while True:
    try:
        user_input = input("Enter you target date in (dd/mm/yyyy): ")
        day, month, year = user_input.split("/")
        day = int(day)
        month = int(month)
        year = int(year)
    except ValueError:
        print("Enter the date, month, year in dd/mm/yyyy format")
    else:
        break


target = date(year, month, day)
now = date.today()
days_until = target - now
print(f"There are {days_until.days} days until {user_input}")
Enter fullscreen mode Exit fullscreen mode

Three things that clicked here at once:

  • try/except ValueError catches the crash when the user types something that can't be split or converted to int — instead of crashing, it loops and asks again
  • else on a try block — I didn't know this existed. It runs only if no exception was raised. Perfect for the break that exits the loop
  • from datetime import date — my first real standard library module. date.today() and date arithmetic (target - now) feel almost magical

Type "christmas" into my program and it says "Enter the date, month, year in dd/mm/yyyy format."
Week 1 me's program would have thrown a wall of red text.


Day 12 — Built-in Libraries: random, datetime, sys

Day 12 was about getting comfortable with Python's standard library. I built a dice roller that tracks your roll history and lets you view it mid-session:

from random import randint
import sys


previous_values = []
global value


def roll():
    '''Checks the user input and then rolls the dice and stores the value in history'''
    while True:
        while True:
            roll_dice = input("Roll the dice?(yes/ no) [press h to view history] ").strip().lower()
            if roll_dice == "yes" or roll_dice == "no" or roll_dice == "h":
                break
        if roll_dice == "no":
            sys.exit()
        elif roll_dice == "h":
            if previous_values:
                check_history()
            else:
                print("There is no history")
        else:
            value = randint(1, 6)
            print(value)
            history(value)


def history(store):
    previous_values.append(store)


def check_history():
    print(previous_values)

#Calling the roll function
roll()
Enter fullscreen mode Exit fullscreen mode

New things that appeared this week:

  • Docstrings'''Checks the user input...''' right under the function definition. First time I've written proper in-code documentation
  • sys.exit() — a clean way to quit a program from inside a function, without needing a flag variable
  • from random import randint — importing just the function I need instead of the whole module

Three focused functions, clear responsibilities, history that persists through the session. This felt like real program design, not just scripts.


Day 13 — The Week 2 Project: A Password Manager

The end-of-week project brought everything together: functions, file I/O, modules, error handling, and a Caesar cipher for encryption. This is the most complex thing I've built so far.

Features:

  • 🔐 Store passwords encrypted to a file
  • 🔍 Retrieve and decrypt them by site name
  • 📁 Persists between sessions using json + pathlib
  • 🔑 Caesar cipher encryption on every stored password
from pathlib import Path
import json
import random
import sys

global file
global key
key = random.randint(3, 25)
file = Path("passwords.txt")
usr_data = {}


#Take command from the user
def command():

    while True:
        com = input("Enter command(store/retrive/'q' to quit): ").strip().lower()
        if com == "store" or com == "retrive" or com == "q":
            break

    if com == "store":
        password_site()
    elif com == "retrive":
        retrive_password()
    else:
        sys.exit()

#Store the password
def password_site():
    while True:
        site_name = input("Enter site name: ")
        passwrd = input("Enter password: ").lower()
        usr_data[site_name] = cipher(passwrd, key)
        while True:
            retry = input("Do you want to store a new password(yes/no)? ").lower()
            if retry == "yes" or retry == "no":
                break
        if retry == "no":
            file.write_text(json.dumps(usr_data, indent = 4))
            print("Saved to file..")
            return

#retrive the password
def retrive_password():
    contents = json.loads(file.read_text())
    site = input("Enter site name to retrive your password: ")
    if site in contents:
       usr_password = decrypt(contents[site], key)
       print(f"Your password for {site} is {usr_password}")
    else:
        print(f"Not found site name: {site}")

#Encrypting the password using ceasar cipher
def cipher(strng, k):
    new_strng = ""
    for char in strng:
        if char.isalpha():
            if char.islower():
                c_num = ((ord(char) - ord("a")) % 26) + ord("a")
                new_strng += chr(c_num)
            elif char.isupper():
                ch_num = ((ord(char) - ord("A")) % 26) + ord("A")
                new_strng += chr(ch_num)
        else:
            new_strng += char
    return new_strng

#Decrypting the password 
def decrypt(pss, k):
    new_pss = ""
    for char in pss:
        if char.isalpha():
            if char.islower():
                char_num = ((ord(char) - ord("a")) % 26) - ord("a")
                new_pss += chr(char_num)
            elif char.isupper():
                chr_num = ((ord(char) - ord("A")) % 26) - ord("A")
                new_pss += chr(chr_num)
        else:
            new_pss += char
    return new_pss

command()
Enter fullscreen mode Exit fullscreen mode

This week's project felt different from last week's. The adventure game was fun. This one felt useful. Real file persistence, real encryption logic, real user commands. I stored a password, closed the program, reopened it, retrieved the password — and it worked. That moment hit differently.


📁 What I Built This Week

Project File Concepts Used
Tip Calculator tip.py Functions, parameters, return values, removesuffix()
Days-Until Calculator days_until.py try/except, datetime, date arithmetic
Dice Roller with History dice.py random, sys, docstrings, list history
Password Manager passwords_manager.py File I/O, json, pathlib, Caesar cipher, all of the above
Adventure Game (refactored) game.py Scope, input validation, cleaner function design

All the code is on GitHub — Week 1 and Week 2, every file:
👉 github.com/Omk4314/progress-on-python


What Actually Clicked This Week

  • One function, one job. Once I started following this rule, my code became easier to read, easier to fix, and easier to build on.
  • try/except changes everything. Programs that handle bad input gracefully feel professional, not just functional.
  • The standard library is enormous. datetime, random, pathlib, json, sys — all built in, nothing to install. I've barely scratched the surface.
  • File I/O makes programs feel real. The moment my password manager wrote to a file and read it back, it stopped feeling like a script and started feeling like software.
  • Refactoring is a skill. Going back to Week 1 code and improving it wasn't boring — it was genuinely satisfying.

What I Want to Learn Next

Week 3 is going to push further:

  • Classes and OOP — I can feel the limits of global variables and I think objects are the answer
  • More on file I/O — reading CSVs, writing logs
  • Bigger projects — something that ties multiple files together properly
  • Maybe some APIs — pulling real data into Python feels like the next unlock

If you're following along or learning Python yourself, drop a comment — I'd love to see what you're building too.

See you in Week 3. 🐍


Two weeks in. The programs are getting real. So is the learning.

Top comments (0)