Unit 1: Python Fundamentals and Environment Setup
1. Python Architecture, Design Philosophy, and Execution Model
Python is a high-level, interpreted, dynamically typed, and garbage-collected programming language conceived by Guido van Rossum in 1989 and officially released in 1991. The language adheres to the design philosophy outlined in PEP 20 (The Zen of Python), emphasizing code readability, explicit logic, syntactic simplicity, and developer productivity:
- "Beautiful is better than ugly."
- "Explicit is better than implicit."
- "Simple is better than complex."
- "Readability counts."
1.1 The CPython Two-Stage Execution Model
Although colloquially termed an "interpreted" language, standard Python (specifically the reference implementation CPython) executes a hybrid compilation and virtual-machine interpretation model:
CODECPython Source-to-Execution Pipeline +-----------------------+ | Source Code (.py) | +-----------------------+ | v (Parser & Bytecode Compiler) +-----------------------+ | Bytecode (.pyc cache) | e.g., __pycache__/script.cpython-312.pyc +-----------------------+ | v (Virtual Machine Dispatch Loop) +-----------------------+ | Python Virtual Machine| (Stack-based PVM executes bytecode opcodes) | (PVM) | +-----------------------+ | v +-----------------------+ | CPU / OS Native Exec | +-----------------------+
- Bytecode Compilation:
- When a Python script or module is imported or executed, the CPython compiler parses the syntax tree and emits platform-independent bytecode (sequences of 16-bit or 8-bit opcodes such as
LOAD_FAST,BINARY_OP,STORE_NAME). - Bytecode files are cached automatically in the
__pycache__/directory with the.pycextension to avoid re-compilation on subsequent runs if source timestamps match.
- When a Python script or module is imported or executed, the CPython compiler parses the syntax tree and emits platform-independent bytecode (sequences of 16-bit or 8-bit opcodes such as
- Virtual Machine Interpretation:
- The Python Virtual Machine (PVM) is a stack-based runtime interpreter written in C.
- It iterates through the compiled bytecode stream within a massive evaluation loop (
_PyEval_EvalFrameDefault), executing opcodes, managing runtime call frames, and invoking native OS system calls.
2. Environment Setup, CLI Tools, and Execution Modes
Developing in Python 3 requires a properly configured runtime environment, system path routing, and familiarity with command-line interfaces.
2.1 The System PATH Environment Variable
- On Windows and Unix operating systems, the
PATHenvironment variable contains an ordered list of directory paths where the operating system searches for executable binaries. - If the directory containing
python.exeand its companionScripts/folder (wherepipresides) is omitted fromPATH, the command prompt will report:
'python' is not recognized as an internal or external command, operable program or batch file. - Modern Windows installers provide an option to "Add Python to PATH" or install the Python Launcher (
py.exe) intoC:\Windows, allowing execution independent of specific path entries.
2.2 The Windows Python Launcher (py.exe)
The Python Launcher manages multiple side-by-side installations of Python (e.g., Python 3.10, 3.11, 3.12, 32-bit vs. 64-bit):
py -0orpy --list: Lists all installed Python versions detected on the host system.py -0porpy --list-paths: Displays registered runtimes alongside their exact executable file paths.py -3.11 script.py: Explicitly launchesscript.pyusing the installed Python 3.11 runtime.- Shebang Line Handling: If a script starts with
#!python3or#!/usr/bin/env python3,py.exeautomatically parses the directive and selects the corresponding interpreter.
2.3 Interactive Mode vs. Script Mode
- Interactive Mode (REPL - Read-Eval-Print Loop):
- Launched by invoking
pythonorpywithout command-line script arguments. - Prompts the user with primary prompt
>>>(and secondary prompt...for multi-line blocks). - Reads an expression, compiles it in memory, evaluates it immediately, and prints non-None return values to stdout. Ideal for rapid experimentation and debugging.
- Launched by invoking
- Script Mode:
- Executes an entire saved text file:
python script.py. - Executes statements sequentially from line 1 to EOF. Does not print expression outcomes unless explicitly wrapped in
print().
- Executes an entire saved text file:
3. Python Syntax Fundamentals: Indentation, Identifiers, and Keywords
3.1 Significant Whitespace and Indentation
Unlike C, C++, or Java that rely on curly braces {} to demarcate code blocks, Python enforces significant whitespace indentation:
- Every nested block (body of
if,for,while,def,class) must be indented relative to its header statement. - PEP 8 Standard: Enforces 4 spaces per indentation level. Mixing tabs and spaces triggers an
IndentationError: unindent does not match any outer indentation levelorTabError: inconsistent use of tabs and spaces in indentation. - A colon (
:) at the end of a statement header indicates that an indented suite follows immediately.
python# Correct block structure using 4 spaces
def compute_magnitude(x, y):
if x > 0:
result = (x**2 + y**2) ** 0.5
return result
else:
return 0.0
3.2 Rules for Valid Identifiers
An identifier is a user-defined name assigned to variables, functions, classes, modules, or packages.
- Must begin with an uppercase or lowercase ASCII letter (
a-z,A-Z) or an underscore (_). - Subsequent characters may include letters, digits (
0-9), or underscores. - Cannot begin with a digit (e.g.,
2varis aSyntaxError, whereasvar2is valid). - Python is strictly case-sensitive:
Total,total, andTOTALrepresent three distinct identifiers. - Cannot be identical to any reserved Python keyword.
3.3 Reserved Python Keywords
Python 3 reserves 35 keywords that possess fixed grammatical meaning in the grammar engine. They cannot be used as identifier names:
pythonimport keyword
print(keyword.kwlist)
# ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await',
# 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except',
# 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
# 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try',
# 'while', 'with', 'yield']
Note: True, False, and None are capitalized; all other keywords are strictly lowercase.
4. The Python Object Model: Variables, References, and Dynamic Typing
4.1 Variables as Reference Names
In low-level languages like C, a variable represents a fixed chunk of named memory where raw binary bits are stored. In Python, variables are reference tags (pointers) bound to heap-allocated objects:
CODEVariable Binding in Python Memory Variable Name (Namespace Tag) Heap-Allocated PyObject [ x ] ------------------------> +-----------------------+ | ob_refcnt: 1 | | ob_type : <class int>| | ob_digit : 42 | +-----------------------+
- When you write
x = 42, Python allocates an integer object representing42in heap memory and binds the namexto point to it. - Executing
y = xdoes not duplicate the integer; it simply bindsyto the same identical object in memory. - Built-in function
id(obj)returns the unique memory address integer of the object in CPython. - Identity operator
isverifies whether two reference variables point to the exact same physical memory address:pythona = [1, 2, 3] b = a c = [1, 2, 3] print(a == c) # True (Value equality check) print(a is c) # False (Distinct memory objects) print(a is b) # True (Identical reference target)
4.2 Dynamic Typing vs. Strong Typing
- Dynamic Typing: Variable names possess no intrinsic data type. A name can be rebound to an object of a completely different type at runtime without declarations:
python
data = 100 # data references an int data = "Active" # data now references a str - Strong Typing: Python does not automatically coerce incompatible types in operations. For example,
'Total: ' + 50raises aTypeError: can only concatenate str (not "int") to str, preventing silent data corruption.
4.3 Mutability vs. Immutability
Every Python object is classified as either mutable or immutable:
- Immutable Objects: State cannot be modified in-place after instantiation. Modifying them creates a new object in memory:
int,float,complex,bool,str,tuple,frozenset,bytes.
- Mutable Objects: Internal contents can be altered in-place without changing memory address (
id()):list,dict,set,bytearray, custom user-defined class instances.
5. Primitive Data Types in Python 3
| Data Type | Description | Constructor / Literal Syntax | Key Characteristics |
|---|---|---|---|
int | Arbitrary-precision integer | x = 10, x = -500, x = int("42") | No overflow limit; grows dynamically to consume available RAM. |
float | Double-precision floating-point | y = 3.14159, y = 1.5e-3 | Implemented as C double (IEEE 754 64-bit; ~15-17 decimal digits precision). |
complex | Complex numbers () | z = 2 + 3j, z.real, z.imag | Formed with real and imaginary parts using suffix j or J. |
bool | Boolean truth value | flag = True, flag = False | Subclass of int (issubclass(bool, int) is True). True == 1, False == 0. |
str | Immutable text sequence | s = "Hello", s = 'World', s = '''Multiline''' | Encoded as Unicode codepoints (UTF-8 / UCS-4 internally). |
NoneType | Absence of value / null | result = None | Singleton object representing no return value or uninitialized state. |
5.1 Arbitrary-Precision Integers
Unlike C/C++ where integers overflow at 32-bit () or 64-bit boundaries, Python 3 integers automatically scale their bit representation dynamically:
pythonbig = 2 ** 100
# 1267650600228229401496703205376 (Calculated accurately with zero overflow)
5.2 Truth Value Testing (Truthy vs. Falsy Values)
Any Python object can be evaluated in a boolean context (e.g., if condition:).
- Falsy Values:
- Constants:
None,False. - Numeric zero:
0,0.0,0j,Decimal(0),Fraction(0, 1). - Empty collections/sequences:
""(empty string),()(empty tuple),[](empty list),{}(empty dict),set()(empty set),range(0).
- Constants:
- Truthy Values:
- Any non-zero number (e.g.,
-1,0.0001). - Any non-empty string (e.g.,
"False"," ","0"are all truthy). - Any populated container (e.g.,
[0],(False,)).
- Any non-zero number (e.g.,
6. Basic Input and Output Operations
6.1 The print() Built-In Function
The print() function formats and writes text to the standard output stream (sys.stdout):
pythonprint(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
*objects: Zero or more expressions separated by commas. Each object is internally converted to a string usingstr().sep: String inserted between adjacent printed arguments (default is a single space' ').end: String appended at the very end of the output (default is a newline character'\n').flush: Boolean specifying whether the output stream buffer should be flushed immediately to the console without buffering.
python# Demonstrating custom separation and end terminator
print("2026", "10", "15", sep="-", end=" | ")
print("Process Completed")
# Output: 2026-10-15 | Process Completed
6.2 The input() Built-In Function
The input([prompt]) function pauses script execution, prints the optional prompt string to standard output, and reads a single line of text from standard input until the user presses Enter:
- Critical Principle:
input()always returns a string (str), even if the user types numeric digits. - To use the entered value in arithmetic calculations, it must be explicitly cast using constructor functions:
python
age = int(input("Enter your age: ")) # Type cast to integer height = float(input("Enter height in m: ")) # Type cast to float - If the user enters a non-digit string into
int(), Python raises aValueError: invalid literal for int() with base 10.
7. Arithmetic Operators and Evaluation Precedence
Python provides a comprehensive set of arithmetic operators governed by mathematical precedence rules:
| Operator | Operation | Example | Result | Evaluation Notes |
|---|---|---|---|---|
+ | Addition | 7 + 3 | 10 | Supports numeric sum and sequence concatenation. |
- | Subtraction | 7 - 3 | 4 | Binary subtraction and unary negation (-x). |
* | Multiplication | 7 * 3 | 21 | Supports numeric multiplication and sequence repetition. |
/ | True Division | 7 / 2 | 3.5 | Always returns a float, even if evenly divisible (4 / 2 -> 2.0). |
// | Floor Division | 7 // 2 | 3 | Rounds down towards (-7 // 2 -> -4). |
% | Modulo (Remainder) | 7 % 3 | 1 | Follows formula: (-7 % 3 -> 2). |
** | Exponentiation | 2 ** 3 | 8 | Right-associative: 2 ** 3 ** 2 = 2 ** 9 = 512. |
7.1 Operator Precedence Hierarchy (Highest to Lowest)
- Parentheses:
(...)(Forces explicit sub-expression evaluation). - Exponentiation:
**(Evaluated right-to-left:4 ** 3 ** 2 = 4 ** (3 ** 2) = 4 ** 9 = 262144). - Unary Operators:
+x,-x,~x. - Multiplicative Group:
*,/,//,%(Evaluated left-to-right). - Additive Group:
+,-(Evaluated left-to-right).
python# Evaluating precedence step-by-step:
expr = 3 + 4 * 2 ** 2
# Step 1 (Exponentiation): 2 ** 2 = 4
# Step 2 (Multiplication): 4 * 4 = 16
# Step 3 (Addition) : 3 + 16 = 19
8. Common Elementary Errors and Debugging Essentials
SyntaxError: Code violates the structural grammar rules of the Python language. Occurs during parsing before execution begins (e.g., missing colon, mismatched parentheses).IndentationError: A subclass ofSyntaxErrorcaused by improper alignment of block suites or mixing tabs and spaces.NameError: Attempting to reference an identifier variable or function name that has not yet been declared, assigned, or imported in the current namespace scope.TypeError: Applying an operation or function to an object of inappropriate type (e.g., addingstrandint, or passing 3 arguments to a function expecting 2).ValueError: An operation or function receives an argument that has the correct data type but an inappropriate value (e.g.,int("twenty")).ZeroDivisionError: Attempting to divide, floor-divide, or modulo any number by zero ().