Skip to content

Commit a96dffb

Browse files
DOC: clarify at() patterns/antipatterns (#81)
Co-authored-by: Lucas Colley <[email protected]>
1 parent e75a97e commit a96dffb

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

Diff for: src/array_api_extra/_funcs.py

+24-7
Original file line numberDiff line numberDiff line change
@@ -649,22 +649,39 @@ class at: # pylint: disable=invalid-name # numpydoc ignore=PR02
649649
650650
Warnings
651651
--------
652-
(a) When you omit the ``copy`` parameter, you should always immediately overwrite
653-
the parameter array::
652+
(a) When you omit the ``copy`` parameter, you should never reuse the parameter
653+
array later on; ideally, you should reassign it immediately::
654654
655655
>>> import array_api_extra as xpx
656656
>>> x = xpx.at(x, 0).set(2)
657657
658-
The anti-pattern below must be avoided, as it will result in different
659-
behaviour on read-only versus writeable arrays::
658+
The above best practice pattern ensures that the behaviour won't change depending
659+
on whether ``x`` is writeable or not, as the original ``x`` object is dereferenced
660+
as soon as ``xpx.at`` returns; this way there is no risk to accidentally update it
661+
twice.
662+
663+
On the reverse, the anti-pattern below must be avoided, as it will result in
664+
different behaviour on read-only versus writeable arrays::
660665
661666
>>> x = xp.asarray([0, 0, 0])
662667
>>> y = xpx.at(x, 0).set(2)
663668
>>> z = xpx.at(x, 1).set(3)
664669
665-
In the above example, ``x == [0, 0, 0]``, ``y == [2, 0, 0]`` and z == ``[0, 3, 0]``
666-
when ``x`` is read-only, whereas ``x == y == z == [2, 3, 0]`` when ``x`` is
667-
writeable!
670+
In the above example, both calls to ``xpx.at`` update ``x`` in place *if possible*.
671+
This causes the behaviour to diverge depending on whether ``x`` is writeable or not:
672+
673+
- If ``x`` is writeable, then after the snippet above you'll have
674+
``x == y == z == [2, 3, 0]``
675+
- If ``x`` is read-only, then you'll end up with
676+
``x == [0, 0, 0]``, ``y == [2, 0, 0]`` and ``z == [0, 3, 0]``.
677+
678+
The correct pattern to use if you want diverging outputs from the same input is
679+
to enforce copies::
680+
681+
>>> x = xp.asarray([0, 0, 0])
682+
>>> y = xpx.at(x, 0).set(2, copy=True) # Never updates x
683+
>>> z = xpx.at(x, 1).set(3) # May or may not update x in place
684+
>>> del x # avoid accidental reuse of x as we don't know its state anymore
668685
669686
(b) The array API standard does not support integer array indices.
670687
The behaviour of update methods when the index is an array of integers is

0 commit comments

Comments
 (0)