Chapter 03 of 24 | Python
Values, types, and variables
Every Python object has a type and a value. A name is a label bound to an object; assignment binds or rebinds a name rather than declaring a permanent storage box with a fixed type.
count = 3
price = 2.50
title = "Notebook"
is_available = True
print(type(count), type(price), type(title), type(is_available))
Common built-in types include integers (int), floating-point numbers (float), text (str), Booleans (bool), and None for the absence of a value. Integers can grow beyond fixed machine-word ranges, while floats use finite-precision binary arithmetic.
Assignment, identity, and equality
first = [1, 2]
second = first
second.append(3)
print(first) # [1, 2, 3]
print(first is second) # True: same object
print(first == second) # True: equal contents
Assignment does not copy a mutable object. Both names above refer to the same list. Equality (==) asks whether values compare equal; identity (is) asks whether two references denote the same object. Use is None to test for the singleton None, not as a general substitute for equality.
Mutability and copying
Strings, integers, and tuples are immutable: an operation that appears to change them creates or returns a different value. Lists, dictionaries, and sets are mutable. A shallow copy duplicates the outer container but still shares nested objects; copy.deepcopy recursively copies many nested structures, but may be inappropriate for resources or objects with custom identity.
import copy
original = [[1], [2]]
shallow = original.copy()
shallow[0].append(9)
print(original) # the inner list is shared
independent = copy.deepcopy(original)
Conversions and numeric precision
whole = int("42")
ratio = float("3.5")
text = str(whole)
print(0.1 + 0.2) # binary floating-point approximation
Conversions can fail, such as int("hello"), or lose information, such as int(3.9), which truncates toward zero. For money, consider integer cents or decimal.Decimal rather than relying on binary floating-point equality. Use math.isclose for approximate comparisons when that matches the domain.
Type hints: documentation, not runtime enforcement
def repeat_label(label: str, count: int) -> list[str]:
return [label] * count
Annotations help readers, editors, and static type checkers understand intended types. Python normally does not enforce them automatically while running. A type checker can find many mismatches before execution, but its result depends on annotations, configuration, and the code it can analyze.
Beginner-to-master progression
- Beginner: identify common types and convert input deliberately.
- Practitioner: reason about mutable aliasing, equality, identity, and shallow copies.
- Advanced: model domain values with immutable dataclasses or validated classes, and use static typing to make invalid states harder to express.
Exercises
- Predict the output when two names refer to one list, then compare it with two independent copies.
- Demonstrate why
0.1 + 0.2 == 0.3may be false and choose an appropriate comparison for a measurement. - Add annotations to a small function and run a type checker if one is available.
Hashability and dictionary keys
Dictionary keys and set elements must be hashable. A hashable object's hash and equality behavior must remain stable while it is used as a key. Immutable built-in values such as strings and integers are common keys; a list is mutable and unhashable. A tuple is hashable only when all its elements are hashable.
locations = {(51.5, -0.1): "London"}
print(locations[(51.5, -0.1)])
# locations[[51.5, -0.1]] would raise TypeError
Custom classes that define equality need a consistent hash policy if instances are to be dictionary keys. Equal objects must have equal hashes. Mutable objects whose equality-relevant fields can change are poor keys because changing them can make dictionary lookup inconsistent with their stored bucket.
Domain modeling and exact values
Use a domain-specific type when primitive values are easy to confuse. A distance in meters and a duration in seconds may both be floats, but adding them is meaningless. A small immutable dataclass or validated wrapper can make units explicit. For monetary calculations, Decimal supports decimal arithmetic, but construction from strings is preferable to construction from an already-rounded float.
from decimal import Decimal
unit_price = Decimal("0.10")
quantity = 3
total = unit_price * quantity
print(total)
Choose precision, rounding mode, and quantization rules according to the domain. Decimal arithmetic is not automatically “correct” for every financial policy; the application's rules must still define how and when values are rounded.
Mastery checkpoint
- Design a hashable immutable value object and test equality/hash consistency.
- Compare float, integer-minor-unit, and Decimal representations for a financial calculation.
- Use a static type checker to find a function call that passes the wrong kind of value, then explain why runtime annotations alone would not reject it.