Fourteen Jupyter notebooks that work out the Python basics from first principles — with experiments, observations, and the mistakes explained rather than hidden.
Most beginner Python material is a list of definitions. This is the opposite: each topic is approached by asking a question, running an experiment, and writing down what actually happened — including the results that were surprising.
Every notebook follows the same six-part structure:
| Section | What it contains |
|---|---|
| Learning objectives | What I should be able to do by the end |
| Introduction | The concept in plain language, and why it exists |
| Detailed explanation | Syntax, rules, behaviour, limitations |
| Experiments | Runnable code, each followed by a written observation |
| Rules & common mistakes | What to remember, and the traps with their fixes |
| Practice tasks | 10+ exercises, from understanding to application |
All outputs are pre-run, so every notebook can be read straight on GitHub without cloning
anything. Error cases are deliberately triggered and caught, so you can see exactly what TypeError: can only concatenate str (not "int") to str looks like rather than just being told about it.
| # | Topic | Notebook | Notes | A question it answers |
|---|---|---|---|---|
| 00 | Main Function | 📓 | 📄 | Why write if __name__ == "__main__": in a language that doesn't need it? |
| 01 | Variables | 📓 | 📄 | Why does changing b also change a? |
| 02 | print() | 📓 | 📄 | Where does the space between printed values come from? |
| 03 | Comments | 📓 | 📄 | Is """...""" really a block comment? |
| 04 | Data Types | 📓 | 📄 | Why is 0.1 + 0.2 != 0.3? |
| 05 | User Input | 📓 | 📄 | Why does my calculator print 1020 instead of 30? |
| 06 | Strings | 📓 | 📄 | Why can't I change one character of a string? |
| 07 | Concatenation | 📓 | 📄 | Why is "5" + 5 an error but 5 + 5.0 isn't? |
| 08 | Escape Characters | 📓 | 📄 | Why did my Windows file path grow a tab character? |
| 09 | Type Casting | 📓 | 📄 | Why does round(2.5) give 2? |
| 10 | Operators | 📓 | 📄 | Why is -17 % 5 equal to 3? |
| 11 | Operator Precedence | 📓 | 📄 | Why is -2 ** 2 equal to -4? |
| 12 | Lists | 📓 | 📄 | Why does [[0]*3]*3 change every row at once? |
| 13 | Random Module | 📓 | 📄 | If it's random, why does the same seed give the same numbers? |
📓 runnable notebook · 📄 condensed written notes
A few findings from the experiments that changed how I write Python:
A variable is a name bound to an object, not a box holding a value.
That one sentence explains aliasing (b = a then mutating b), re-typing (x = 4 then
x = "four"), and shadowing (list = [1,2] breaking list("abc")) all at once — three "special
cases" that turn out to be one rule. (notebook 01)
Precedence bugs don't crash. Every other topic fails loudly with a traceback. a + b + c / 3
returns a perfectly valid wrong answer, and age >= 18 and has_id or is_member grants access to a
17-year-old. This is why the practical conclusion is "parenthesise anything a reader would have to
look up", not "memorise the table". (notebook 11)
Python converts implicitly only when there is exactly one sensible answer. int + float has
one answer, so it's automatic. "5" + 5 has two, so it's a TypeError. int(3.7) has two, so
Python picks truncation and provides round() for the other. Once that clicked, the conversion
rules stopped feeling arbitrary. (notebooks 04, 09)
[[0]*3]*3 is almost always a bug. * on a list of lists copies the references, so all
three rows are the same object and grid[0][0] = 1 changes the whole column. [[0]*3 for _ in range(3)] evaluates a fresh row each time. (notebook 12)
Short-circuiting is a feature to rely on, not an optimisation detail. It's the entire mechanism
behind if items and items[0] == x, and it's why and/or return one of their operands rather
than a boolean — which is what makes name or "Guest" idiomatic. (notebook 10)
repr() is the debugging tool for invisible characters. Every baffling "yes" != "yes"
comparison turns out to be a trailing \n, and print() will never show it to you. (notebook 08)
git clone https://github.com/Yugalpoudel07/Python_Fundamentals.git
cd Python_Fundamentals
pip install -r requirements.txt
jupyter notebookNo third-party libraries are used in any notebook — everything runs on the standard library, so
jupyter is the only requirement. Python 3.8 or newer (f-strings with = need 3.8).
A note on notebook 05 (User Input): a live input() call would freeze a notebook waiting for a
keyboard, so that notebook's first cell replaces input with a scripted stand-in that reads from a
list of canned answers and echoes them like a terminal. Delete that one cell and every example
becomes genuinely interactive — nothing else changes.
A note on notebook 00: it writes a few small .py files to the working directory to demonstrate
the difference between running and importing a module. They're listed in .gitignore.
Python_Fundamentals/
├── notebooks/ 14 Jupyter notebooks, outputs included
│ ├── 00_Python_Main_Function.ipynb
│ ├── 01_Variables.ipynb
│ └── ...
├── notes/ 14 condensed Markdown revision notes
│ ├── 00_Python_Main_Function.md
│ └── ...
├── requirements.txt
├── LICENSE
└── README.md
The notes/ files are the quick-reference version: definitions, syntax tables, rules and mistake
tables without the experiments. Useful for revision once the notebook has been worked through.
The topic coverage and terminology follow the W3Schools Python Tutorial, which was the primary reference throughout. Every notebook links the specific pages it draws on in its closing section.
All explanations, examples, experiments and observations in this repository are original — written while working through the material, not copied from it. Where an experiment produced a result I didn't expect, that's recorded as an observation rather than smoothed over.
Additional references consulted: the Python Standard Library documentation and PEP 8.
MIT — use these freely for learning or teaching.