How to broadcast arrays without copying data in NumPy (with Code)
The Short Answer (TL;DR)
Use np.broadcast_to to expose compatible array data through a read-only view with a larger shape. Broadcasting can avoid a repeated input allocation, but a new arithmetic result still needs storage unless an appropriate output buffer is supplied.
import numpy as np
x = np.array([1.0,2.0,3.0]); view = np.broadcast_to(x,(4,3))
print(view.shape, np.shares_memory(x,view), view.flags.writeable)
Detailed Implementation
This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.
python -m pip install numpy==2.5.4
from pathlib import Path
import numpy as np
# One vector of three channel offsets, represented as float64.
offsets = np.array([1.0,2.0,3.0],dtype=np.float64)
view = np.broadcast_to(offsets,(4,3))
measurements = np.arange(12,dtype=np.float64).reshape(4,3)
corrected = np.empty_like(measurements)
np.add(measurements,view,out=corrected)
shared = np.shares_memory(offsets,view)
text = (f"source bytes={offsets.nbytes}; logical view bytes={view.nbytes}\n"
f"shape={view.shape}; strides={view.strides}; shares_memory={shared}; writable={view.flags.writeable}\n"
"CORRECTED\n"+np.array2string(corrected)+"\n")
Path("broadcast-view-audit.txt").write_text(text,encoding="utf-8")
print(text)
The audit reports shape (4, 3), strides (0, 8), shared memory True and writable False. Source data use 24 bytes; the view has 96 logical bytes. Corrected rows are [1, 3, 5], [4, 6, 8], [7, 9, 11] and [10, 12, 14].
Which shapes can broadcast together?
Compare dimensions from the right. Aligned dimensions must be equal or one of them must be 1; missing leading dimensions behave as size 1. A vector of shape (3,) therefore fits a target shape (4, 3). A column of shape (2, 1) fits (2, 3), while the vector of length 3 cannot fit (2, 2). The full example keeps channel offsets on the final dimension so their interpretation is explicit.
How does the larger view avoid repeating the input?
The four-by-three view has a zero stride along its first dimension. Moving to another row therefore selects the same three source values rather than a copied row. np.shares_memory confirms overlap for this nonempty example. The vector stores 24 bytes of float64 data, while the view describes 96 logical bytes. The view also needs a small array object; this is not a claim that creating it allocates no memory whatsoever.
Why does nbytes not report the unique backing allocation?
An array's nbytes is its element count multiplied by its item size. Repeated references through a zero-stride view still count toward that logical size. The 96-byte figure therefore does not establish that 96 new data bytes were allocated. The example records source bytes, shape, strides and memory overlap together. Empty arrays have no elements to overlap, so an overlap test on an empty view is not useful evidence about its backing source.
Can the view be edited?
np.broadcast_to returns a read-only view. Several displayed elements can refer to one source location, so treating them as independently writable would be misleading. The checks confirm that assigning through the view fails. Changing the source vector itself updates every corresponding view row. If independent writable cells are required, make an explicit copy and budget for the full repeated array; do not force the view's writeable flag.
Does broadcasting also remove the arithmetic output allocation?
Adding two broadcast-compatible inputs still produces a full-sized result. The implementation allocates corrected once and passes it as the ufunc out buffer. That controls where the result is stored; it does not shrink the four-by-three result or guarantee that arbitrary operations need no temporary work. Measurements and offsets remain unchanged. The independent loop-based reference confirms the numerical result without using broadcasting.
When can broadcasting use too much memory?
A compact input view can describe an enormous logical output. Pairwise calculations with added singleton axes can produce a matrix far larger than either input. Estimate the result element count and dtype item size before materializing it, and use blocks or a reduction appropriate to the problem when necessary. Lists may also need conversion to arrays; the no-repeated-data observation here applies to the existing NumPy source vector.
Mathematical Context
For this two-dimensional view, the address offset of element (i,j) is i times a zero row stride plus j times an eight-byte column stride. Thus all four values with the same column j refer to the same source element. The logical element count is 4 times 3, so logical nbytes is 12 times 8 = 96, while the original three-element float64 vector has 24 data bytes. A distinct arithmetic result still has twelve output values. These byte counts concern this dtype and shape rather than a timing benchmark.
\[ \operatorname{offset}(i,j)=i\cdot0+j\cdot8,\qquad N_{\mathrm{logical}}=4\cdot3 \]
Reproducibility
Executed with Python 3.12.14; numpy 2.5.4. Automated checks confirm the stated output properties.