<style>
.reveal {
font-size: 200%; /* make the font smaller, actually */
}
.reveal ul, .reveal ol {
display: block;
}
.reveal pre {
width: fit-content;
max-width: 90%;
}
</style>
# What's New in Python 3.13
# and NumPy 2
Lehman Garrison (SCC)
Sciware #37
Feb. 20, 2025
---
## Sciware Rules of Engagement
### Goal:
Activities where participants all actively work to foster an environment which encourages participation across experience levels, coding language fluency, *technology choices*\*, and scientific disciplines.
<small>\*though sometimes we try to expand your options</small>
---
## Sciware Rules of Engagement
- Avoid discussions between a few people on a narrow topic
- Provide time for people who haven't spoken to speak/ask questions
- Provide time for experts to share wisdom and discuss
- Work together to make discussions accessible to novices
<small>
(These will always be a work in progress and will be updated, clarified, or expanded as needed.)
</small>
---
# Python 3.13

---
## Python 3.13
- Released on October 7, 2024
- Highlights
1. Improvements to built-in modules
1. An improved interactive interpreter
1. Improved error messages
1. An experimental "free-threaded" mode
1. An experimental just-in-time (JIT) compiler
---
## Built-in Modules
- Improvements to built-in modules
- `os.process_cpu_count()`: an affinity-aware version of `os.cpu_count()`, useful on the cluster
- `breakpoint()` now works correctly when placed at the end of a block
- `venv` module now creates SCM (e.g. git) ignore files
- Read more here: https://docs.python.org/3/whatsnew/3.13.html
---
## Interactive Interpreter
- New interactive interpreter (i.e interactive prompt) based on [PyPy](https://pypy.org/)
- Prompt and tracebacks have color
- Multiline pasting and editing
- Multiline history


---
## Interactive Interpreter

---
## Interactive Interpeter
<img src=https://hackmd.io/_uploads/H1SO5XKd1l.png style="width: 70%">
---
## Interactive Interpreter
- Interactive demo
- Multiline pasting and editing
```python
from pathlib import path
for fn in Path('/home/lgarrison/sciware').iterdir():
print(fn, fn.stat().st_size)
```
- Multiline history
---
## Improved Error messages
- Suggestions for misspelled keyword arguments

- Nice errors when a user module shadows an installed module

---
## Experimental Free-Threaded Python
- Python 3.13 offers a way to build Python without the Global Interpreter Lock (GIL)
- Try it yourself:
- `uv run -p 3.13t`, or
- `conda install -c conda-forge python-freethreading`
- Read much more here: https://py-free-threading.github.io/
- See especially the ["Compatibility Status Tracking"](https://py-free-threading.github.io/tracking/) page
---
## Free-Threading: Background
- Threads are a way to execute more than one part of your program in parallel
- Python supports threads, but the GIL means only one can run at a time
<div style="background:white; display: inline-block;">
<img src=https://hackmd.io/_uploads/B1amzVFOyl.gif>
</div>
<small>https://en.wikipedia.org/wiki/Global_interpreter_lock</small>
- The GIL is why we use, e.g., the `multiprocessing` module instead of the `threading` module
- For users, `multiprocessing` makes it harder to share data and write certain kinds of parallel code
- Spawning processes safely and efficiently is challening
---
## Free-Threaded Python: What to Know
- For users:
- If a library (e.g. PyTorch) explicitly supports free-threaded Python and encourages you to use it, give it a try!
- Also good for advanced users who want to parallelize a Python-heavy workload
- For developers:
- Packages compiled against CPython: need to provide free-threaded builds
- Pure Python packages: no build changes needed, but need to consider thread safety of your package (e.g. shared global state may now be subject to race conditions)
---
## Free-Threaded Python
- Eventually, free-threaded Python will probably be the default
- Single-threaded code is currently slower in free-threaded builds
- Popular packages are still adding support
- Expect to see more use of `concurrent.futures.ThreadPoolExecutor`
- Less use of `multiprocessing` and `concurrent.futures.ProcessPoolExecutor`
---
## Experimental JIT
- 3.13 has an experimental, opt-in just-in-time (JIT) compiler
- The JIT produces a machine-code version of a function the first time that it's called ("just in time")
- The goal: Python is now much faster!
- The reality: not really (at least in 3.13)
---
## Experimental JIT
```python
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n-i-1):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
```
| Language | Time |
| -------- | ---- |
| Python | 3.70 sec |
| JIT Python | 3.06 sec |
| Rust | 0.06 sec |
- Note that this is function is *pure Python* code, and is not calling any compiled libraries like NumPy. The Experimental JIT is about optimizing pure Python code.
- Source: https://blog.miguelgrinberg.com/post/is-python-really-that-slow
---
## Experimental JIT
- A bit like free-threaded Python, this will probably improve over time and become the default in the future.
- For scientific Python, most work is already done in:
- compiled extensions (e.g. NumPy), or
- specialized JIT (e.g. JAX, Numba, PyTorch),
so the impact will be narrow/more specialized.
---
## What Python Should I Use?
- Now that Python 3.13 is out, what version should I use?

---
## What Python Should I Use?
- For users:
- using 3.12 (the second-most recent) is pretty safe, unless you need a feature in 3.13.
- 3.13 support is already pretty widespread.
- For developers:
- should try to test and develop against all supported versions (currently 3.9--3.13)
- See the Scientific Python Ecosystem Coordination's [SPEC0](https://scientific-python.org/specs/spec-0000/) for a alternative (more aggressive) deprecation schedule
---
## Python 3.13
Questions or comments about Python 3.13? Any experiences with 3.13?
Next up: NumPy 2
---
# NumPy 2
<img src="https://hackmd.io/_uploads/HyfYWfE5Jl.png" style="width: 30%">
---
## NumPy 2
- Released on June 16, 2024
- First major version release since 2006
- API and ABI changes
- Some Python code using NumPy 1 will not work with NumPy 2
- Any extension compiled against NumPy 1 will not work with NumPy 2
- About 100 members of the main `np` namespace have been deprecated, removed, or moved to a new place
- Array API standard
- Performance improvements
- Read more:
- https://numpy.org/devdocs/release/2.0.0-notes.html
- https://numpy.org/devdocs/numpy_2_0_migration_guide.html
- https://numpy.org/devdocs/dev/depending_on_numpy.html#numpy-2-abi-handling
---
## NumPy 2 API Changes
- New features
- A new variable-length string dtype, `StringDType` and a new `numpy.strings` namespace with performant ufuncs for string operations,
- Support for `float32` and `longdouble` in all `numpy.fft` functions (SciPy FFT still better)
- Support for the "array API" standard in the main numpy namespace.
- Changes
- dtype promotion rules
- Changes to the `copy` kwarg in `np.asarray()`
---
## NumPy 2 & the Array API
- NumPy 2 adopts the [Python array API Standard](https://data-apis.org/array-api/2023.12/index.html)
> One unintended consequence [...] has been fragmentation in multidimensional array (a.k.a. tensor) libraries [...] Choices include NumPy, Tensorflow, PyTorch, Dask, JAX, CuPy, MXNet, Xarray, and others.
> The APIs of each of these libraries are largely similar, but with enough differences that it’s quite difficult to write code that works with multiple (or all) of these libraries. This array API standard aims to address that issue, by specifying an API for the most common ways arrays are constructed and used.
---
## NumPy 2 & the Array API
- New functions, or new array API variants of existing functions
- `np.linalg.diagonal` and `np.linalg.trace` now supplement `np.diagonal` and `np.trace` with slightly different behavior;
- "differ in the default axis selection which define 2-D sub-arrays"
- `np.acos`, `np.acosh`, etc, now alias `np.arccos`, `np.arccosh`, etc.
---
## NumPy 2 & the Array API

<small>https://numpy.org/doc/stable/reference/generated/numpy.unique_counts.html</small>
---
## NumPy 2 Data Type Promotion
- `np.float32(3) + 3.` now returns a `float32` when it previously returned a `float64`.
- `np.array([3], dtype=np.float32) + np.float64(3)` will now return a `float64` array. (The higher precision of the scalar is not ignored.)
- Read [NEP50](https://numpy.org/neps/nep-0050-scalar-promotion.html) for details
- "Values must never influence result type."
- "NumPy scalars and 0-D arrays should behave consistently with their N-D counterparts."
---
## NumPy 2 `copy` kwarg
- The `copy` kwarg to `np.asarray()` now has 3 possible values:
- `copy=False`: never copy, raise an exception if a copy is needed
- `copy=None`: try to not copy, but copy if necessary
- `copy=True`: always copy
- Very useful for writing high-performance code that minimizes copies
- `np.asarray(..., copy=False)` is now preferred over `np.array(..., copy=False)`
---
## NumPy 2 Performance
- Sorting functions (`sort`, `argsort`, `partition`, `argpartition`) have been accelerated through the use of the Intel x86-simd-sort and Google Highway libraries, and may see large (hardware-specific) speedups,
```console!
❯ srun -C rome --pty zsh
❯ taskset -c 0 uv run --with 'numpy<2' python -m timeit -s 'import numpy as np; a = np.random.default_rng().permutation(10**7)' 'np.sort(a)'
1 loop, best of 5: 780 msec per loop
❯ taskset -c 0 uv run --with 'numpy>=2' python -m timeit -s 'import numpy as np; a = np.random.default_rng().permutation(10**7)' 'np.sort(a)'
1 loop, best of 5: 209 msec per loop
```
- macOS Accelerate support and binary wheels for macOS >=14, with significant performance improvements for linear algebra operations on macOS, and wheels that are about 3 times smaller.
---
## NumPy 2: Understanding Errors
- When using old Python packages, you may see one of the following errors.
- Example 1: missing attribute in `numpy` module:
```text
>>> import astropy.table
...
File "/mnt/home/lgarrison/tmp/.venv/lib/python3.9/site-packages/astropy/units/quantity_helper/function_helpers.py", line 78, in <module>
np.prod, np.product, np.cumprod, np.cumproduct,
File "/mnt/home/lgarrison/tmp/.venv/lib/python3.9/site-packages/numpy/__init__.py", line 410, in __getattr__
raise AttributeError("module {!r} has no attribute "
AttributeError: module 'numpy' has no attribute 'product'
```
- If possible, try upgrading the offending package:
```text
❯ pip install -U astropy
```
- If that fails, try downgrading to NumPy 1:
```text
❯ pip install 'numpy < 2'
```
- Hint: check if using NumPy 2:
```text
>>> import numpy as np
>>> np.__version__
'2.0.2'
```
---
## NumPy 2: Understanding Errors
- Example 2:
```text
>>> import astropy.wcs
A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.0.2 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.
If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.
Traceback (most recent call last): File "<stdin>", line 1, in <module>
File "/mnt/home/lgarrison/tmp/.venv/lib/python3.9/site-packages/astropy/wcs/__init__.py", line 26, in <module>
from .wcs import *
...
```
- Same solution: if possible, try upgrading the offending package:
```text
❯ pip install -U astropy
```
- If that fails, try downgrading to NumPy 1:
```text
❯ pip install 'numpy < 2'
```
---
## NumPy 2: For Package Developers
- Read the [NumPy 2 Migration Guide](https://numpy.org/devdocs/numpy_2_0_migration_guide.html#numpy-2-0-migration-guide)
- For pure Python packages
- Recommend to support NumPy 1 and 2 at least for the next few months (see [SPEC0](https://scientific-python.org/specs/spec-0000/#support-window))
- Ideally test against both 1 and 2
- For compiled extensions
- Compiling against NumPy 2 should provide compatibility with 1 and 2
- Remember that extensions compiled against NumPy 1 will *not* work with NumPy 2
<!--  -->

---
## NumPy 2
Any questions/comments about NumPy 2?
Any experiences with NumPy 2?
{"title":"What's New in Python 3.13 and NumPy 2","description":"SciWare #37","slideOptions":"{}","contributors":"[{\"id\":\"27014d88-fe86-4e5b-98f4-00fd2f5611b4\",\"add\":18478,\"del\":5895},{\"id\":\"593188ed-3426-49b2-9cd5-47c99af9945f\",\"add\":2470,\"del\":198}]"}