From: David C. <da...@ar...> - 2006-10-18 10:59:31
|
Hi there, I've just managed to nail down a bug which took me nearly two whole days to find: this is coming from an unexpected (at least from me) behaviour of numpy. I understand that if foo is a numpy array, doing bar = foo makes no copy, and whenever you change the value of foo, you change the value of bar: import numpy as N foo = N.linspace(0, 4, 5) bar = foo print foo[1] bar[1] = -1 print foo[1] => prints 1 and -1. Now, if I do: bar += 1 print bar is foo prints True But if I do bar = bar + 1, then bar is not a copy of foo anymore. Is this intended ? This looks really confusing to me, and I would like to know what the precise rules about copy vs alias are ? Cheers, David |
From: Sven S. <sve...@gm...> - 2006-10-18 11:47:44
|
David Cournapeau schrieb: > Hi there, > > I've just managed to nail down a bug which took me nearly two whole > days to find: this is coming from an unexpected (at least from me) > behaviour of numpy. You have all my sympathy, I tripped over something similar not too long ago, so welcome to the club. > Now, if I do: > > bar += 1 > print bar is foo > > prints True > > But if I do bar = bar + 1, then bar is not a copy of foo anymore. Is > this intended ? This looks really confusing to me, and I would like to > know what the precise rules about copy vs alias are ? > Yes it's intended; as far as I understand the python/numpy syntax, <+> is an operator, and that triggers assignment by copy (even if you do something trivial as bar = +foo, you get a copy, if I'm not mistaken), while <+=> is syntactically not really an operator. AFAIK it's sole purpose is really to _not_ make a copy to save memory (well, it also looks nice ;-). You'll need somebody else to tell you the _precise_ rules, though... -sven |
From: David C. <da...@ar...> - 2006-10-18 12:05:01
|
Sven Schreiber wrote: > > Yes it's intended; as far as I understand the python/numpy syntax, <+> > is an operator, and that triggers assignment by copy (even if you do > something trivial as bar = +foo, you get a copy, if I'm not mistaken), > So basically, whenever you have foo = expr with expr is a numpy expression containing foo, you trigger a copy ? David |
From: Sven S. <sve...@gm...> - 2006-10-18 13:51:13
|
David Cournapeau schrieb: > Sven Schreiber wrote: >> Yes it's intended; as far as I understand the python/numpy syntax, <+> >> is an operator, and that triggers assignment by copy (even if you do >> something trivial as bar = +foo, you get a copy, if I'm not mistaken), >> > So basically, whenever you have > > foo = expr > > with expr is a numpy expression containing foo, you trigger a copy ? > David, I would tend to confirm your conjecture, but given its generality I should not pretend to really know all about that stuff. It could be, for example, that the user may specify inside the expression that she wants a view, not a copy, But I don't know if that's really possible. Anybody else available to help out? -sven |
From: A. M. A. <per...@gm...> - 2006-10-18 15:08:15
|
On 18/10/06, David Cournapeau <da...@ar...> wrote: > Sven Schreiber wrote: > > > > Yes it's intended; as far as I understand the python/numpy syntax, <+> > > is an operator, and that triggers assignment by copy (even if you do > > something trivial as bar = +foo, you get a copy, if I'm not mistaken), > > > So basically, whenever you have > > foo = expr > > with expr is a numpy expression containing foo, you trigger a copy ? No. "=" never copies, but "+" does: when you do "A+B" you produce a new, freshly-allocated array, which you can then store (a reference to) in any variable you like, including A or B. So M = M+1 makes a copy because "M+1" is a new matrix, which you are assigning to M. Unfortunately, this means if you do: M = 2*(M+1) python makes the new matrix M+1, then makes the new matrix 2*(M+1), discards M+1, and sets M to point to 2*(M+1). If you want to avoid all this copying, you can use python's in-place operators: M += 1 M *= 2 This is actually a standard difficulty people have with python, made more obvious because you're working with mutable arrays rather than immutable scalars. A. M. Archibald |
From: Charles R H. <cha...@gm...> - 2006-10-18 16:50:18
|
On 10/18/06, David Cournapeau <da...@ar...> wrote: > > Sven Schreiber wrote: > > > > Yes it's intended; as far as I understand the python/numpy syntax, <+> > > is an operator, and that triggers assignment by copy (even if you do > > something trivial as bar = +foo, you get a copy, if I'm not mistaken), > > > So basically, whenever you have > > foo = expr > > with expr is a numpy expression containing foo, you trigger a copy ? Yes. Numpy generates a temporary where the expression results are kept, the temporary is then assigned to foo. This can be inefficient, but knowing when you may overwrite data can be complicated. For instance: foo = dot(foo,foo) Can't be done in place because values needed later on in the dot evaluation would be overwritten. Chuck |
From: Travis O. <oli...@ie...> - 2006-10-18 17:15:21
|
David Cournapeau wrote: > Sven Schreiber wrote: > >> Yes it's intended; as far as I understand the python/numpy syntax, <+> >> is an operator, and that triggers assignment by copy (even if you do >> something trivial as bar = +foo, you get a copy, if I'm not mistaken), >> >> > So basically, whenever you have > > foo = expr > > with expr is a numpy expression containing foo, you trigger a copy ? > I think you are better off understanding that "=" is a name binding operation while "+=" calls a special method that allows in-place adding. Thus, bar += foo calls bar.__iadd__(bar, foo) which gives the opportunity to add foo to bar in-place while bar = bar + foo adds bar to foo (which results in a new array that then gets re-bound to the name bar). The '=' sign is not an operator. Perhaps this will help you see the difference. It's good to know what kinds of things trip people up. We can target tutorials and FAQs to those things. -Travis |
From: Robert K. <rob...@gm...> - 2006-10-18 17:13:38
|
David Cournapeau wrote: > bar += 1 > print bar is foo > > prints True > > But if I do bar = bar + 1, then bar is not a copy of foo anymore. Is > this intended ? Yes, very much so! If it were otherwise Guido would never have added the augmented assignment operators. From the reference manual: http://docs.python.org/ref/augassign.html """An augmented assignment expression like x += 1 can be rewritten as x = x + 1 to achieve a similar, but not exactly equal effect. In the augmented version, x is only evaluated once. Also, when possible, the actual operation is performed in-place, meaning that rather than creating a new object and assigning that to the target, the old object is modified instead.""" > This looks really confusing to me, and I would like to > know what the precise rules about copy vs alias are ? I'm not going to go through all of the functions in numpy, but here are some (unorganized) rules of thumb: * Any operations with regular operators + - / * // ** ~ ^ & | << >> < > == <=, etc. will put their results into new arrays. If the expression is on the RHS of a regular assignment, just ignore the LHS of the assignment; even if the name on the LHS is the same as a name on the RHS, the expression is evaluated, the new array is created and *then* the new array is assigned to the LHS name. * Augmented assignment operators will operate in-place. * Functions and methods should state that they operate in-place in their docstrings. * The asarray(), asanyarray(), etc. functions will return the input array if it is already suitable. * Slicing, reshaping, transposing and similar structural operations create new array objects, but they are generally views, not copies of the data. -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco |
From: Christopher B. <Chr...@no...> - 2006-10-19 21:00:21
|
Robert Kern wrote: > From the reference manual: > > http://docs.python.org/ref/augassign.html > > """An augmented assignment expression like x += 1 can be rewritten as x = x + 1 > to achieve a similar, but not exactly equal effect. In the augmented version, x > is only evaluated once. Also, when possible, the actual operation is performed > in-place, meaning that rather than creating a new object and assigning that to > the target, the old object is modified instead.""" I've always thought this was a mistake -- it is a source of weird errors and bugs. AFAIC, the augmented assignments should ONLY work with mutable objects, and ALWAYS do the operation in place. But then you couldn't write: i = 1 i += 1 Because python numbers are immutable. I think the problem here is that augmented assignment is solving two distinct problems: in place operations and nice syntax for incrementing. Oh well, it's not that big a deal, and usually the confusion causes errors that show up right away. -Chris -- Christopher Barker, Ph.D. Oceanographer NOAA/OR&R/HAZMAT (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chr...@no... |