1.1 History and Features of Python
Python was created by Guido van Rossum at Centrum Wiskunde & Informatica (CWI) in the Netherlands and released to the public in 1991. Guido designed the language around one uncompromising, central idea: code is read far more often than it is written. Therefore, a programming language should be optimized for the human developer reading and maintaining it, not just the physical computer executing machine instructions.
That guiding philosophy is immortalized in a collection of 19 software design aphorisms built directly into every Python interpreter called "The Zen of Python" (PEP 20). Any developer can view it at any time in the REPL by executing:
import this
Its most celebrated, foundational principles include:
- "Beautiful is better than ugly."
- "Explicit is better than implicit."
- "Simple is better than complex."
- "Complex is better than complicated."
- "Readability counts."
- "There should be one-- and preferably only one --obvious way to do it."
- "Now is better than never."
Syntactic Grammar: Enforced Whitespace & Indentation
You can see this readability philosophy in Python's core syntax. Languages like C, C++, and Java use semicolons (;) to terminate statements and curly braces ({ }) to mark blocks of code. Python deliberately drops both.
Instead, Python uses indentation — the whitespace at the start of a line — as the actual grammar of the language. If a line is indented one level deeper than the line above it, Python understands that it belongs inside that previous line (inside a function, an if-statement, a loop, and so on). This is not an optional style suggestion or linter recommendation; it is strictly enforced by the interpreter. Two lines that are supposed to be in the same block but are indented differently will cause an error before the program even runs.
In most other languages, badly-formatted code can still run (it just looks messy). In Python, badly-formatted indentation simply won't run at all. This is intentional — it forces every Python codebase, written by any programmer anywhere in the world, to share a consistent visual structure.
The Five Architectural Pillars of Python
- Interpreted: There is no separate "compile" step you have to run yourself; the interpreter reads and executes your code directly. Behind the scenes, it compiles to bytecode, but the workflow feels instantaneous.
- Dynamically Typed: You never write
int xorString name; Python figures out the type from the value itself at runtime. - High-Level & Memory-Managed: You never manually allocate or free memory; Python's garbage collector (combining Reference Counting with Generational Cyclic Garbage Collection) does it for you.
- Multi-Paradigm: The same language comfortably supports procedural (functions), object-oriented (classes, inheritance, polymorphism), and functional programming styles (lambdas, list comprehensions, map/filter).
- Enormous Ecosystem: The
piptool connects you to hundreds of thousands of free, ready-to-use libraries on the Python Package Index (PyPI), spanning Web Development (Django, FastAPI), Data Engineering (Pandas, Polars), and Artificial Intelligence (PyTorch, TensorFlow).
💡 Placement & Interview Deep-Dive
- What is CPython? CPython is the reference implementation of Python written in C. When you download Python from python.org, you are installing CPython. Other alternative implementations exist: PyPy (which uses a Just-In-Time compiler for 5-10x speedups), Jython (compiles Python into Java bytecode running on the JVM), and IronPython (runs on .NET CLR).
- What is the Global Interpreter Lock (GIL)? In CPython, the GIL is a mutual-exclusion lock that prevents multiple native OS threads from executing Python bytecode simultaneously. This ensures thread-safety around CPython's reference counting memory management. For CPU-bound parallel processing across multiple CPU cores, Python programs use the
multiprocessingmodule instead of threads.
1.2 Installing Python & the Interpreter
To write Python, you need the Python interpreter installed on your computer — a small program that knows how to read .py files and carry out their instructions. It is free to download from python.org for Windows and, on most Mac and Linux machines, already comes pre-installed.
Once installed, you interact with it in two main ways:
1. The REPL (Read–Eval–Print Loop)
You open the REPL by typing python or python3 into a terminal window with nothing after it. This drops you into an interactive prompt (indicated by >>>) where you can type one line of Python, press Enter, and immediately see the result — perfect for quickly testing an idea, checking how a function behaves, or using Python as a calculator:
>>> 2 ** 10
1024
>>> "ReadyToGo".replace("Go", "Fly")
'ReadyToFly'
>>> import math
>>> math.gcd(48, 18)
6
Inside the REPL, the special variable _ (single underscore) automatically stores the result of the last evaluated expression:
>>> 15 * 4
60
>>> _ + 10
70
2. Running a Complete Script File
The second way is running a complete file with python script.py, which executes every line in that file from top to bottom, exactly as a finished production program would.
Use the REPL to experiment one line at a time; use a saved .py file whenever you want something you can run again, share, or build on later.
Useful Interpreter Command-Line Flags
python -m <module>: Runs a library module as a script (e.g.python -m venv .venv,python -m pip install requests, orpython -m http.server 8000).python -i script.py: Runs the script and then drops immediately into the interactive REPL with all the script's variables and functions still loaded into memory. Invaluable for live debugging!python -c "code": Executes a Python command string directly from the terminal without saving a file (e.g.python -c "import sys; print(sys.version)").
1.3 Structure of a Python Program
Unlike C or Java, a Python file does not need a special starting function such as main(). Whatever is written at the top level of the file — not indented inside anything — simply runs in order, from the first line to the last, the moment the file is executed.
A function definition (introduced with def) does not run its own body immediately; it just teaches Python what the function will do once it is later called by name.
Annotated Program Skeleton
# SCRIPT.PY
# comments start with a hash symbol
name = "World" # top-level statement, runs immediately
def greet(n): # function definition (body does NOT run yet)
print(f"Hello, {n}!") # indented = inside the function
greet(name) # function call — THIS is what actually runs greet()
Indentation Rules & PEP 8 Standard
The four-space indentation convention shown above is not arbitrary — it's the community standard (documented in a style guide called PEP 8), and virtually every Python codebase you will ever read follows it.
Mixing tabs and spaces, or using an inconsistent number of spaces at the same block level, is one of the most common early syntax errors beginners hit. In Python 3, mixing tabs and spaces in the same file raises a fatal TabError: inconsistent use of tabs and spaces in indentation.
💡 Placement & Interview Deep-Dive: The if __name__ == '__main__': Idiom
Every Python module contains a built-in special variable named __name__. When you execute a Python file directly from the terminal:
python script.py
The interpreter automatically assigns __name__ = "__main__". However, if another script imports your file as a module:
import script
Python sets __name__ = "script" (the actual module name). Therefore, standard industry Python scripts use this guard:
def main():
print("Application running...")
if __name__ == "__main__":
main() # Runs ONLY when executed directly, NOT when imported by another file!
This allows your Python files to serve dual purposes: as standalone executable command-line tools AND as reusable importable modules without side effects!
1.4 How Python Code Executes
It's a common misconception that Python is "not compiled at all." In reality, when you run a .py file, Python first silently translates your source code into an intermediate, lower-level form called bytecode.
This step happens automatically every single time you run the script — you never trigger it yourself, and Python often caches the result inside a hidden folder named __pycache__ so it doesn't have to redo identical work next time.
That bytecode is then handed to the Python Virtual Machine (PVM), a program built into the interpreter itself, which reads the bytecode one instruction at a time and actually carries it out.
The Runtime vs Development Trade-Off
This is why Python is generally slower at runtime than a fully compiled language like C — there's an extra translation layer working at every step — but it's also why Python is so fast to write, test, and change: you never wait for a separate, explicit compilation stage the way you do in Java or C++.
💡 Inspecting Python Bytecode with the dis Module
You can inspect the exact bytecode instructions generated by Python using the built-in dis (disassembler) module:
import dis
def add(a, b):
return a + b
dis.dis(add)
Output generated by the CPython compiler:
2 0 RESUME 0
2 LOAD_FAST 0 (a)
4 LOAD_FAST 1 (b)
6 BINARY_OP 0 (+)
10 RETURN_VALUE
Notice how CPython operates as a Stack Machine: it pushes a and b onto the evaluation stack, executes the BINARY_OP, and returns the result!