-
-
Notifications
You must be signed in to change notification settings - Fork 9.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: Nditer as context manager #9998
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -319,8 +319,9 @@ def iter_add_py(x, y, out=None): | |
addop = np.add | ||
it = np.nditer([x, y, out], [], | ||
[['readonly'], ['readonly'], ['writeonly','allocate']]) | ||
for (a, b, c) in it: | ||
addop(a, b, out=c) | ||
with it: | ||
for (a, b, c) in it: | ||
addop(a, b, out=c) | ||
return it.operands[2] | ||
|
||
Here is the same function, but following the C-style pattern:: | ||
|
@@ -344,13 +345,12 @@ def outer_it(x, y, out=None): | |
|
||
it = np.nditer([x, y, out], ['external_loop'], | ||
[['readonly'], ['readonly'], ['writeonly', 'allocate']], | ||
op_axes=[range(x.ndim)+[-1]*y.ndim, | ||
[-1]*x.ndim+range(y.ndim), | ||
op_axes=[list(range(x.ndim)) + [-1] * y.ndim, | ||
[-1] * x.ndim + list(range(y.ndim)), | ||
None]) | ||
|
||
for (a, b, c) in it: | ||
mulop(a, b, out=c) | ||
|
||
with it: | ||
for (a, b, c) in it: | ||
mulop(a, b, out=c) | ||
return it.operands[2] | ||
|
||
>>> a = np.arange(2)+1 | ||
|
@@ -381,6 +381,32 @@ def luf(lamdaexpr, *args, **kwargs): | |
>>> luf(lambda i,j:i*i + j/2, a, b) | ||
array([ 0.5, 1.5, 4.5, 9.5, 16.5]) | ||
|
||
If operand flags `"writeonly"` or `"readwrite"` are used the operands may | ||
be views into the original data with the WRITEBACKIFCOPY flag. In this case | ||
nditer must be used as a context manager. The temporary | ||
data will be written back to the original data when the `` __exit__`` | ||
function is called but not before:: | ||
|
||
>>> a = np.arange(6, dtype='i4')[::-2] | ||
>>> with nditer(a, [], | ||
... [['writeonly', 'updateifcopy']], | ||
... casting='unsafe', | ||
... op_dtypes=[np.dtype('f4')]) as i: | ||
... x = i.operands[0] | ||
... x[:] = [-1, -2, -3] | ||
... # a still unchanged here | ||
>>> a, x | ||
array([-1, -2, -3]), array([-1, -2, -3]) | ||
|
||
It is important to note that once the iterator is exited, dangling | ||
references (like `x` in the example) may or may not share data with | ||
the original data `a`. If writeback semantics were active, i.e. if | ||
`x.base.flags.writebackifcopy` is `True`, then exiting the iterator | ||
will sever the connection between `x` and `a`, writing to `x` will | ||
no longer write to `a`. If writeback semantics are not active, then | ||
`x.data` will still point at some part of `a.data`, and writing to | ||
one will affect the other. | ||
|
||
""") | ||
|
||
# nditer methods | ||
|
@@ -524,6 +550,13 @@ def luf(lamdaexpr, *args, **kwargs): | |
|
||
""") | ||
|
||
add_newdoc('numpy.core', 'nditer', ('close', | ||
""" | ||
close() | ||
|
||
Resolve all writeback semantics in writeable operands. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps reference the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed (in doc-nditer PR) |
||
|
||
""")) | ||
|
||
|
||
############################################################################### | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,8 @@ | |
|
||
Whenever you change one index, you break the ABI (and the ABI version number | ||
should be incremented). Whenever you add an item to one of the dict, the API | ||
needs to be updated. | ||
needs to be updated in both setup_common.py and by adding an appropriate | ||
entry to cversion.txt (generate the hash via "python cversions.py". | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: missing paren There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is "best practice" when fixing a merged PR, a new PR or modifying this one again? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't modify an existing PR once it's merged. What I normally do is keep working in the same branch, but open a new PR There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed (in doc-nditer PR) |
||
|
||
When adding a function, make sure to use the next integer not used as an index | ||
(in case you use an existing index or jump, the build will stop and raise an | ||
|
@@ -349,6 +350,8 @@ | |
'PyArray_ResolveWritebackIfCopy': (302,), | ||
'PyArray_SetWritebackIfCopyBase': (303,), | ||
# End 1.14 API | ||
'NpyIter_Close': (304,), | ||
# End 1.15 API | ||
} | ||
|
||
ufunc_types_api = { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be
NpyIter_Deallocate
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed (in doc-nditer PR)