Skip to main content

Python Basics

Master the fundamental concepts of Python programming

Python basics cover the four building blocks every first-year course tests: variables, primitive types, operators, and standard input/output. CS50P, MIT 6.100L, and Stanford CS106A graders accept submissions only when these primitives behave exactly as the spec defines. The fastest way to lose points is misusing `int` vs `str` or forgetting that `input()` always returns a string.

1. Variables bind names to objects, not memory addresses

A Python variable is a label attached to an object. Assigning `x = 5` does not reserve a memory slot called `x`. Python creates the integer object `5`, then points the name `x` at it. This explains a behavior that confuses every student in week 2: assigning `y = x` and then `x = 10` leaves `y` still pointing at `5`. The integer object never changed; only the name `x` got re-pointed.

This model has three practical consequences. Reassignment is cheap because nothing copies. Type changes mid-script are legal: `x = 5` then `x = "hello"` runs without error. And mutable objects shared by two names update for both names, which is the source of the most common pandas and NumPy bugs later on.

**Naming rules** that Gradescope checks: lowercase with underscores (`student_score`), no leading digit, no Python keywords (`class`, `lambda`, `if`). Single underscores are convention for "throwaway" (`_, value = pair`). Double-leading-underscore triggers name mangling in classes and is reserved for OOP work.

Example

                      
                        # Run with: python variables.py
# Demonstrates name binding, not memory copying

x = 5  # name "x" points to int object 5
y = x  # name "y" points to the SAME object 5
print(f"x={x}, y={y}, same object: {x is y}")  # True - both names, one object

x = 10  # "x" is now repointed to a new int object 10
print(f"x={x}, y={y}, same object: {x is y}")  # False - y still on 5

# Mutable case: this is where bugs hide
list_a = [1, 2, 3]  # name "list_a" points to a list object
list_b = list_a     # "list_b" points to the SAME list
list_b.append(99)   # mutates the shared object in place
print(f"list_a={list_a}")  # [1, 2, 3, 99] - surprise mutation
print(f"list_b={list_b}")  # [1, 2, 3, 99]
                      
                    

2. The 4 primitive types every CS50P problem uses

Python ships **four primitive types** for beginner work: `int`, `float`, `str`, and `bool`. Each has a literal syntax (`42`, `3.14`, `"hi"`, `True`) and a constructor for conversion (`int("42")`, `float("3.14")`, `str(42)`, `bool(0)`). The constructors are the source of the second-most-common autograder fail: passing a `float` literal to `int()` truncates toward zero (`int(3.9)` returns `3`), not rounds. Use `round(3.9)` when the spec asks for nearest integer.

The `bool` type is a subclass of `int`. `True == 1` and `False == 0` evaluate to `True`. This matters for arithmetic: `sum([True, False, True])` returns `2`, which is the idiomatic way to count matches in a list. Six values are falsy: `0`, `0.0`, `""`, `None`, `[]`, `{}`. Everything else is truthy, including the string `"False"`, which is a trap on many quizzes.

The `str` type is immutable. `name = "John"; name[0] = "T"` raises `TypeError`. Build a new string with slicing or `replace()`. Strings carry seven methods graded courses test often: `.lower()`, `.upper()`, `.strip()`, `.split()`, `.replace()`, `.startswith()`, `.endswith()`.

Example

                      
                        # Run with: python types.py
# The four primitive types and their conversions

age_str = "25"           # str literal from input or a CSV cell
age_int = int(age_str)   # str -> int (raises ValueError if non-numeric)
print(type(age_str), type(age_int))

price = 19.99            # float literal
dollars = int(price)     # float -> int TRUNCATES (gives 19, not 20)
rounded = round(price)   # use round() for nearest integer
print(f"truncated={dollars}, rounded={rounded}")

# bool IS an int subclass - common autograder gotcha
votes = [True, True, False, True, False]
print(f"yes votes: {sum(votes)}")  # prints 3

# Falsy values to memorize for "if" tests
for val in [0, 0.0, "", None, [], {}, "False"]:
    print(f"{val!r:>8} is truthy? {bool(val)}")  # last one prints True
                      
                    

3. Operators: arithmetic, comparison, and the order students forget

Python has **5 arithmetic operators** that matter for homework: `+`, `-`, `*`, `/`, `//`, `%`, and `**`. Integer division (`//`) and modulo (`%`) appear in every loop-counter problem and every "is this number even" check. The expression `n % 2 == 0` returns `True` when `n` is even, which graders use in roughly half of the introductory looping assignments at MIT 6.100L and DATA 100.

The **division operator** `/` always returns a float. `10 / 2` gives `5.0`, not `5`. This breaks autograder tests that expect `int` output. Either cast with `int(10 / 2)` or use `//` from the start. Floor division of negative numbers rounds toward negative infinity: `-7 // 2` gives `-4`, not `-3`. This caught half the CS50P submissions for the "Math Interpreter" problem set.

Comparison and logical operators chain in Python in a way C and Java do not allow. The expression `0 <= score <= 100` evaluates as `(0 <= score) and (score <= 100)`. Writing it the C way as `0 <= score <= 100` works in Python and is the recommended style. The `and`, `or`, `not` keywords short-circuit: `(x != 0) and (y / x > 1)` skips the second test when `x == 0`, which prevents `ZeroDivisionError`.

Example

                      
                        # Run with: python operators.py
# Operator edge cases that lose points on Gradescope

print(10 / 3)    # 3.333... ALWAYS a float
print(10 // 3)   # 3 (floor division, returns int)
print(10 % 3)    # 1 (remainder)
print(2 ** 10)   # 1024 (exponent, NOT XOR like in C)

# Negative floor division rounds toward negative infinity
print(-7 // 2)   # -4 (not -3)
print(-7 % 2)    # 1 (sign matches divisor)

# Chained comparison: idiomatic in Python
score = 87
if 0 <= score <= 100:
    print("valid score")

# Short-circuit evaluation prevents the second test from crashing
x, y = 0, 10
if x != 0 and y / x > 1:  # second clause skipped, no ZeroDivisionError
    print("never reached")
else:
    print("x guarded correctly")
                      
                    

4. f-strings: the only string formatting graders accept now

F-strings (formatted string literals) replaced `%` formatting and `.format()` for graded work after Python 3.6. CS50P, DATA 100, and CSE 163 rubrics all show f-strings in the reference solutions. Three reasons: less typing, embedded expressions, and built-in format specifiers for decimals, padding, and alignment.

The syntax is `f"text {expression:format_spec}"`. Inside the braces, any valid Python expression runs: arithmetic (`f"{price * 1.08}"`), method calls (`f"{name.upper()}"`), conditionals (`f"{count} item{'s' if count != 1 else ''}"`). The format spec after the colon controls width, precision, and alignment. The four specs students need most: `:.2f` for 2 decimal places, `:,` for thousands separator, `:>10` for right-aligned width 10, `:0>3` for zero-padding to 3 digits.

Debug expressions (`f"{x=}"`) print both name and value, which replaces every `print("x =", x)` line. This was added in Python 3.8 and is the fastest way to inspect state during a `pdb`-style trace.

Example

                      
                        # Run with: python fstrings.py
# F-string patterns graders look for in CS50P / DATA 100 solutions

name = "Alice"
price = 1234.5678
count = 7

# Basic interpolation
print(f"Hello, {name}")

# Expression evaluation inside braces
print(f"Total with tax: {price * 1.08:.2f}")  # 1333.31 (2 decimals)

# Thousands separator and alignment
print(f"Balance: ${price:,.2f}")              # $1,234.57
print(f"|{name:>10}|")                         # |     Alice| right-aligned
print(f"|{name:^10}|")                         # |  Alice   | centered

# Zero-padding for IDs and dates
for day in [1, 12, 145]:
    print(f"Day-{day:0>3}")  # Day-001, Day-012, Day-145

# Debug syntax (Python 3.8+) for tracing state
result = price * 1.08
print(f"{result=:.2f}")  # prints: result=1333.31
                      
                    

5. Input and output: where most CS50P submissions fail the autograder

The `input()` function **always returns a string**, even when the prompt asks for a number. Forgetting to cast is the single most reported reason CS50P submissions fail Check50 with `ValueError` or `TypeError`. The fix is one line: wrap `input()` in `int()` or `float()` before storing the result. Wrap that in a `try/except ValueError` block if the spec says to handle non-numeric input gracefully.

The `print()` function takes four keyword arguments graders test often: `sep` (separator between values, default `" "`), `end` (suffix, default `"\n"`), `file` (write target, default `sys.stdout`), and `flush` (force-write the buffer). Setting `end=""` suppresses the newline, which Gradescope tests for in fill-in-the-blank prompts. Setting `sep=","` produces CSV output without manually concatenating strings.

**Reading multi-line input** uses `sys.stdin.read()` or a `while` loop with `try/except EOFError`. HackerRank and many auto-graders pipe a file into stdin; calling `input()` repeatedly until `EOFError` is raised is the canonical pattern. Course CS50P provides the `cs50` library which wraps this, but the stdlib pattern below works on every grader.

Example

                      
                        # Run with: echo "42" | python io_demo.py
# Input/output patterns that pass Gradescope and Check50

# input() returns a string - ALWAYS cast it
raw = input("Enter your age: ")
try:
    age = int(raw)  # ValueError if user typed "abc"
except ValueError:
    print(f"Invalid input: {raw!r}")
    raise SystemExit(1)  # exit with error code for grader

print(f"In 10 years you turn {age + 10}")

# print() keyword arguments graders test
print("a", "b", "c", sep="-")        # a-b-c
print("loading", end="")              # no newline
print("...done")                       # appears on same line

# CSV output without string concatenation
row = ["alice", 87, "A"]
print(*row, sep=",")  # alice,87,A
                      
                    

Common pitfalls

Forgetting that `input()` returns a string and trying to do math: `age = input(); age + 1` raises `TypeError: can only concatenate str (not "int") to str`.

Cast on the same line: `age = int(input("Enter age: "))`. Wrap in `try/except ValueError` if non-numeric input is expected.

Using `=` (assignment) inside an `if` condition when `==` (comparison) was intended. Python catches this with `SyntaxError`, unlike C where it silently assigns and tests truthiness.

Read aloud: "if x equals 5" is `==`, "set x to 5" is `=`. The error message points to the exact line.

Comparing floats with `==`: `0.1 + 0.2 == 0.3` evaluates to `False` because IEEE 754 rounding produces `0.30000000000000004`.

Use `math.isclose(a, b)` from the stdlib, or compare with a tolerance: `abs(a - b) < 1e-9`. Standard practice in DATA 100 and CS229.

Mutating a list while iterating over it (`for x in items: items.remove(x)`) skips elements because the index shifts under the loop.

Iterate over a copy (`for x in items[:]:`) or build a new list with a comprehension: `items = [x for x in items if keep(x)]`.

Treating `None` as `False` in tests like `if value:`. A `None` is falsy, but so are `0`, `""`, and `[]`. The test passes for all four, which hides bugs.

Test identity explicitly: `if value is None:` or `if value is not None:`. PEP 8 names this as the preferred form.

When to use python basics

Reach for these basics whenever a problem set asks for variables, type conversion, simple arithmetic, or stdin/stdout interaction. For loops and branches, move to control flow. For reusable logic, move to functions.

Get expert help

Stuck on a python basics assignment? These DMPH service pages match this topic:

Need Help?

Having trouble with this topic on an assignment? Our Python developers ship working code plus a walkthrough that helps you explain the code in class.