From da2ec4b0db989c0a2da41d0d71e4add96dc324bf Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 11:12:37 +1100 Subject: [PATCH 1/6] Add Type Hints section to More Language Features lecture Adds a compact section on Python type hints to the python_advanced_features lecture, covering: - Basic syntax (function parameters, return types, variable annotations) - Common built-in types and container type syntax - Demonstration that hints are not enforced at runtime - Why type hints matter (readability, IDE support, error checking, LLM code) - Connection to scientific Python and JIT compilation Closes #343 --- lectures/python_advanced_features.md | 102 ++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index 9d2cb574..5508af1f 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -29,7 +29,7 @@ It's here 1. as a reference, so we can link back to it when required, and 1. for those who have worked through a number of applications, and now want to learn more about the Python language -A variety of topics are treated in the lecture, including iterators, decorators and descriptors, and generators. +A variety of topics are treated in the lecture, including iterators, type hints, decorators and descriptors, and generators. ## Iterables and Iterators @@ -459,6 +459,106 @@ Overall, `*args` and `**kargs` are used when *defining a function*; they enable The difference is that functions with `*args` will be able to take *positional arguments* with an arbitrary size, while `**kargs` will allow functions to take arbitrarily many *keyword arguments*. +## Type Hints + +```{index} single: Python; Type Hints +``` + +Python is a *dynamically typed* language, meaning you don't need to declare the types of variables. + +(See our {doc}`earlier discussion ` of dynamic versus static types.) + +However, Python supports optional **type hints** (also called type annotations) that allow you to indicate the expected types of variables, function parameters, and return values. + +Type hints were introduced in Python 3.5 and have become increasingly common in modern Python code. + +```{note} +Type hints are **ignored by the Python interpreter at runtime** --- they do not affect how your code executes. +They are purely informational and serve as documentation for humans and tools. +``` + +### Basic Syntax + +Type hints use the colon `:` to annotate variables and parameters, and the arrow `->` to annotate return types. + +Here is a simple example: + +```{code-cell} python3 +def greet(name: str, times: int) -> str: + return (name + '! ') * times + +greet('hello', 3) +``` + +In this function definition: + +- `name: str` indicates `name` is expected to be a string +- `times: int` indicates `times` is expected to be an integer +- `-> str` indicates the function returns a string + +You can also annotate variables directly: + +```{code-cell} python3 +x: int = 10 +y: float = 3.14 +name: str = 'Python' +``` + +### Common Types + +The most frequently used type hints are the built-in types: + +| Type | Example | +|-----------|----------------------------------| +| `int` | `x: int = 5` | +| `float` | `x: float = 3.14` | +| `str` | `x: str = 'hello'` | +| `bool` | `x: bool = True` | +| `list` | `x: list = [1, 2, 3]` | +| `dict` | `x: dict = {'a': 1}` | + +For containers, you can specify the types of their elements: + +```{code-cell} python3 +prices: list[float] = [9.99, 4.50, 2.89] +counts: dict[str, int] = {'apples': 3, 'oranges': 5} +``` + +### Hints Don't Enforce Types + +An important point for new Python programmers: type hints are **not enforced** at runtime. + +Python will not raise an error if you pass the "wrong" type: + +```{code-cell} python3 +def add(x: int, y: int) -> int: + return x + y + +# Works fine, despite passing strings +add('foo', 'bar') +``` + +This is a key difference from statically typed languages like C or Java, where mismatched types cause compilation errors. + +### Why Use Type Hints? + +If Python ignores them, why bother? + +1. **Readability**: Type hints make function signatures self-documenting. A reader immediately knows what types a function expects and returns. +2. **Editor support**: IDEs like VS Code use type hints to provide better autocompletion, error detection, and inline documentation. +3. **Error checking**: Tools like [mypy](https://mypy.readthedocs.io/) and [pyrefly](https://pyrefly.org/) analyze type hints to catch bugs *before* you run your code. +4. **LLM-generated code**: Large language models frequently produce code with type hints, so understanding the syntax helps you read and use their output. + +### Type Hints in Scientific Python + +Type hints connect to the {doc}`need for speed ` discussion: + +* High-performance libraries like [JAX](https://jax.readthedocs.io/) and [Numba](https://numba.pydata.org/) rely on knowing variable types to compile fast machine code. +* While these libraries infer types at runtime rather than reading Python type hints directly, the *concept* is the same --- explicit type information enables optimization. +* As the Python ecosystem evolves, the connection between type hints and performance tools is expected to grow. + +For now, the main benefit of type hints in day-to-day Python is **clarity and tooling support**, which becomes increasingly valuable as programs grow in size. + ## Decorators and Descriptors ```{index} single: Python; Decorators From f4ac10d53178e867f6ee21efef887498bb483cef Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 11:21:59 +1100 Subject: [PATCH 2/6] Minor: join note text into single paragraph line --- lectures/python_advanced_features.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index 5508af1f..548e527b 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -473,8 +473,7 @@ However, Python supports optional **type hints** (also called type annotations) Type hints were introduced in Python 3.5 and have become increasingly common in modern Python code. ```{note} -Type hints are **ignored by the Python interpreter at runtime** --- they do not affect how your code executes. -They are purely informational and serve as documentation for humans and tools. +Type hints are **ignored by the Python interpreter at runtime** --- they do not affect how your code executes. They are purely informational and serve as documentation for humans and tools. ``` ### Basic Syntax From 6c745ac6516a1db688b434312a6c9802782af8a1 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 13:23:29 +1100 Subject: [PATCH 3/6] Fix section heading capitalization per qe-writing-006 Lowercase section headings to capitalize only the first word and proper nouns (e.g., Python), per QuantEcon style rules. --- lectures/python_advanced_features.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index 548e527b..ca364b9d 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -459,7 +459,7 @@ Overall, `*args` and `**kargs` are used when *defining a function*; they enable The difference is that functions with `*args` will be able to take *positional arguments* with an arbitrary size, while `**kargs` will allow functions to take arbitrarily many *keyword arguments*. -## Type Hints +## Type hints ```{index} single: Python; Type Hints ``` @@ -476,7 +476,7 @@ Type hints were introduced in Python 3.5 and have become increasingly common in Type hints are **ignored by the Python interpreter at runtime** --- they do not affect how your code executes. They are purely informational and serve as documentation for humans and tools. ``` -### Basic Syntax +### Basic syntax Type hints use the colon `:` to annotate variables and parameters, and the arrow `->` to annotate return types. @@ -503,7 +503,7 @@ y: float = 3.14 name: str = 'Python' ``` -### Common Types +### Common types The most frequently used type hints are the built-in types: @@ -523,7 +523,7 @@ prices: list[float] = [9.99, 4.50, 2.89] counts: dict[str, int] = {'apples': 3, 'oranges': 5} ``` -### Hints Don't Enforce Types +### Hints don't enforce types An important point for new Python programmers: type hints are **not enforced** at runtime. @@ -539,7 +539,7 @@ add('foo', 'bar') This is a key difference from statically typed languages like C or Java, where mismatched types cause compilation errors. -### Why Use Type Hints? +### Why use type hints? If Python ignores them, why bother? @@ -548,7 +548,7 @@ If Python ignores them, why bother? 3. **Error checking**: Tools like [mypy](https://mypy.readthedocs.io/) and [pyrefly](https://pyrefly.org/) analyze type hints to catch bugs *before* you run your code. 4. **LLM-generated code**: Large language models frequently produce code with type hints, so understanding the syntax helps you read and use their output. -### Type Hints in Scientific Python +### Type hints in scientific Python Type hints connect to the {doc}`need for speed ` discussion: From e868fbba43c12e12d56fffef9829b42175a5e00f Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 13:25:11 +1100 Subject: [PATCH 4/6] Fix heading capitalization lecture-wide per qe-writing-006 Apply sentence case to all section headings (##, ###, ####) across the entire lecture, not just the new Type Hints section. Only the first word and proper nouns (e.g., Python) are capitalized. --- lectures/python_advanced_features.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index ca364b9d..094910ae 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -31,7 +31,7 @@ It's here A variety of topics are treated in the lecture, including iterators, type hints, decorators and descriptors, and generators. -## Iterables and Iterators +## Iterables and iterators ```{index} single: Python; Iteration ``` @@ -130,7 +130,7 @@ next(nikkei_data) next(nikkei_data) ``` -### Iterators in For Loops +### Iterators in for loops ```{index} single: Python; Iterators ``` @@ -286,14 +286,14 @@ tags: [raises-exception] max(y) ``` -## `*` and `**` Operators +## `*` and `**` operators `*` and `**` are convenient and widely used tools to unpack lists and tuples and to allow users to define functions that take arbitrarily many arguments as input. In this section, we will explore how to use them and distinguish their use cases. -### Unpacking Arguments +### Unpacking arguments When we operate on a list of parameters, we often need to extract the content of the list as individual arguments instead of a collection when passing them into functions. @@ -400,7 +400,7 @@ To summarize, when `*list`/`*tuple` and `**dictionary` are passed into *function The difference is that `*` will unpack lists and tuples into *positional arguments*, while `**` will unpack dictionaries into *keyword arguments*. -### Arbitrary Arguments +### Arbitrary arguments When we *define* functions, it is sometimes desirable to allow users to put as many arguments as they want into a function. @@ -558,7 +558,7 @@ Type hints connect to the {doc}`need for speed ` discussion: For now, the main benefit of type hints in day-to-day Python is **clarity and tooling support**, which becomes increasingly valuable as programs grow in size. -## Decorators and Descriptors +## Decorators and descriptors ```{index} single: Python; Decorators ``` @@ -584,7 +584,7 @@ It's very easy to say what decorators do. On the other hand it takes a bit of effort to explain *why* you might use them. -#### An Example +#### An example Suppose we are working on a program that looks something like this @@ -675,7 +675,7 @@ Now the behavior of `f` is as we desire, and the same is true of `g`. At the same time, the test logic is written only once. -#### Enter Decorators +#### Enter decorators ```{index} single: Python; Decorators ``` @@ -776,7 +776,7 @@ In the last two lines we see that `miles` and `kms` are out of sync. What we really want is some mechanism whereby each time a user sets one of these variables, *the other is automatically updated*. -#### A Solution +#### A solution In Python, this issue is solved using *descriptors*. @@ -827,7 +827,7 @@ car.kms Yep, that's what we want --- `car.kms` is automatically updated. -#### How it Works +#### How it works The names `_miles` and `_kms` are arbitrary names we are using to store the values of the variables. @@ -845,7 +845,7 @@ For example, after `car` is created as an instance of `Car`, the object `car.mil Being a property, when we set its value via `car.miles = 6000` its setter method is triggered --- in this case `set_miles`. -#### Decorators and Properties +#### Decorators and properties ```{index} single: Python; Decorators ``` @@ -898,7 +898,7 @@ A generator is a kind of iterator (i.e., it works with a `next` function). We will study two ways to build generators: generator expressions and generator functions. -### Generator Expressions +### Generator expressions The easiest way to build generators is using *generator expressions*. @@ -954,7 +954,7 @@ In fact, we can omit the outer brackets in this case sum(x * x for x in range(10)) ``` -### Generator Functions +### Generator functions ```{index} single: Python; Generator Functions ``` @@ -1101,7 +1101,7 @@ def g(x): x = x * x ``` -### Advantages of Iterators +### Advantages of iterators What's the advantage of using an iterator here? From de3b830cde46829b7cac9c6920b4d7466cd0d66a Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 13:36:01 +1100 Subject: [PATCH 5/6] Fix bold/italic usage per qe-writing-005 style rule Change bold to italic for emphasis (not definitions): - 'skip it on first pass' (pre-existing) - 'ignored by the Python interpreter at runtime' - 'not enforced' - 'clarity and tooling support' --- lectures/python_advanced_features.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index 094910ae..f23301a7 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -22,7 +22,7 @@ kernelspec: ## Overview -With this last lecture, our advice is to **skip it on first pass**, unless you have a burning desire to read it. +With this last lecture, our advice is to *skip it on first pass*, unless you have a burning desire to read it. It's here @@ -473,7 +473,7 @@ However, Python supports optional **type hints** (also called type annotations) Type hints were introduced in Python 3.5 and have become increasingly common in modern Python code. ```{note} -Type hints are **ignored by the Python interpreter at runtime** --- they do not affect how your code executes. They are purely informational and serve as documentation for humans and tools. +Type hints are *ignored by the Python interpreter at runtime* --- they do not affect how your code executes. They are purely informational and serve as documentation for humans and tools. ``` ### Basic syntax @@ -525,7 +525,7 @@ counts: dict[str, int] = {'apples': 3, 'oranges': 5} ### Hints don't enforce types -An important point for new Python programmers: type hints are **not enforced** at runtime. +An important point for new Python programmers: type hints are *not enforced* at runtime. Python will not raise an error if you pass the "wrong" type: @@ -556,7 +556,7 @@ Type hints connect to the {doc}`need for speed ` discussion: * While these libraries infer types at runtime rather than reading Python type hints directly, the *concept* is the same --- explicit type information enables optimization. * As the Python ecosystem evolves, the connection between type hints and performance tools is expected to grow. -For now, the main benefit of type hints in day-to-day Python is **clarity and tooling support**, which becomes increasingly valuable as programs grow in size. +For now, the main benefit of type hints in day-to-day Python is *clarity and tooling support*, which becomes increasingly valuable as programs grow in size. ## Decorators and descriptors From 78e37d16c3d297a327a82c72c9e59102135eeeed Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Mon, 23 Mar 2026 14:30:21 +1100 Subject: [PATCH 6/6] Address Copilot review: fix version text and type mismatch example --- lectures/python_advanced_features.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lectures/python_advanced_features.md b/lectures/python_advanced_features.md index f23301a7..40e8c63b 100644 --- a/lectures/python_advanced_features.md +++ b/lectures/python_advanced_features.md @@ -470,7 +470,8 @@ Python is a *dynamically typed* language, meaning you don't need to declare the However, Python supports optional **type hints** (also called type annotations) that allow you to indicate the expected types of variables, function parameters, and return values. -Type hints were introduced in Python 3.5 and have become increasingly common in modern Python code. +Type hints were introduced starting in Python 3.5 and have evolved in subsequent versions. +All of the syntax shown here works in Python 3.9 and later. ```{note} Type hints are *ignored by the Python interpreter at runtime* --- they do not affect how your code executes. They are purely informational and serve as documentation for humans and tools. @@ -533,10 +534,12 @@ Python will not raise an error if you pass the "wrong" type: def add(x: int, y: int) -> int: return x + y -# Works fine, despite passing strings -add('foo', 'bar') +# Passes floats — Python doesn't complain +add(1.5, 2.7) ``` +The hints say `int`, but Python happily accepts `float` arguments and returns `4.2` --- also not an `int`. + This is a key difference from statically typed languages like C or Java, where mismatched types cause compilation errors. ### Why use type hints?