I have a big problem with numpy, numarray and Numeric (all version) If I'm using the script at the bottom, I obtain these results: var1 before function is [3 4 5] var2 before function is 1 var1 after function must be [3 4 5] is [ 9 12 15] <------ problem var2 after function must be 1 is 1 var3 must be the [9 12 15] is [ 9 12 15] var4 must be the 'toto' is toto I'm very surprised by the line noted. I always thinking that the input variable didn't change the variable itself outside the function. It's the comportement for var2 but var1 is changed and it's a big problem (at least for me). The only object in python with this behavior are the numeric object (Numeric, numarray or numpy), with list or other kind of object I have the expected result (the var1 before to go inside the function) I can't keep the input variable if I'm not doing a copy before to call a function... Is it normal and so do I have to do a copy of the input data each time I'm calling a function? Thanks Nicolas #!/usr/bin/env python import numpy print "numpy version ", numpy.__version__ def test(var1,var2): #print "var1 input function is",var1 #print "var2 input function is",var2 var1 *=3 var2 = 'toto' return var1,var2 var1=numpy.array([3,4,5]) var2=1 print "var1 before function is ",var1 print "var2 before function is ",var2 var3,var4=test(var1,var2) print "var1 after function must be [3 4 5] is ",var1 print "var2 after function must be 1 is ", var2 print "var3 must be the [9 12 15] is ", var3 print "var4 must be the 'toto' is ", var4
On Thursday 08 February 2007 16:21:09 humufr@yahoo.fr wrote:
I'm very surprised by the line noted. I always thinking that the input variable didn't change the variable itself outside the function.
Except that in this particular case, you explicitly change the input array itself by using an inplace operator.
I can't keep the input variable if I'm not doing a copy before to call a function...
what about just using var1 = var1*3 ? That way, the initial array is left intact, and var1 inside your function is multiplied by 3.
humufr@yahoo.fr wrote:
I have a big problem with numpy, numarray and Numeric (all version)
If I'm using the script at the bottom, I obtain these results:
var1 before function is [3 4 5] var2 before function is 1 var1 after function must be [3 4 5] is [ 9 12 15] <------ problem var2 after function must be 1 is 1 var3 must be the [9 12 15] is [ 9 12 15] var4 must be the 'toto' is toto
I'm very surprised by the line noted. I always thinking that the input variable didn't change the variable itself outside the function.
To save yourself confusion, you need to understand the difference between mutable and immutable types. Mutable types can be changed inside of a function call. You also need to understand that = is a "name-binding operation only" it does not change objects.
Is it normal and so do I have to do a copy of the input data each time I'm calling a function?
Yes, it's very normal, if your function does an "in-place" operation on a mutable type. Consider the following code: def test(var1, var2): var1[0] *= 3 # this accesses the 0'th element of var1 and alters it. var2 = 'toto' # this makes a new object and names it with var2 # whatever was passed in is gone return var1, var2 test([1,2,3],[1,2]) will return [3,2,3], 'toto' -Travis
Thank you to both of you for this explanatin. I'm coming from the fortran world and so I never had to deal with this before... Sorry to have polluate the list for a stupid things Thanks again that clarify the problem Nicolas Le Thursday 08 February 2007 17:01:36 Travis Oliphant, vous avez écrit :
humufr@yahoo.fr wrote:
I have a big problem with numpy, numarray and Numeric (all version)
If I'm using the script at the bottom, I obtain these results:
var1 before function is [3 4 5] var2 before function is 1 var1 after function must be [3 4 5] is [ 9 12 15] <------ problem var2 after function must be 1 is 1 var3 must be the [9 12 15] is [ 9 12 15] var4 must be the 'toto' is toto
I'm very surprised by the line noted. I always thinking that the input variable didn't change the variable itself outside the function.
To save yourself confusion, you need to understand the difference between mutable and immutable types. Mutable types can be changed inside of a function call.
You also need to understand that = is a "name-binding operation only" it does not change objects.
Is it normal and so do I have to do a copy of the input data each time I'm calling a function?
Yes, it's very normal, if your function does an "in-place" operation on a mutable type.
Consider the following code:
def test(var1, var2): var1[0] *= 3 # this accesses the 0'th element of var1 and alters it. var2 = 'toto' # this makes a new object and names it with var2 # whatever was passed in is gone return var1, var2
test([1,2,3],[1,2])
will return
[3,2,3], 'toto'
-Travis
_______________________________________________ Numpy-discussion mailing list Numpy-discussion@scipy.org http://projects.scipy.org/mailman/listinfo/numpy-discussion
humufr@yahoo.fr wrote:
Thank you to both of you for this explanatin. I'm coming from the fortran world and so I never had to deal with this before...
Sorry to have polluate the list for a stupid things
No need to apologize. All programming systems take some getting-used-to at first before they become natural. -- 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
Your question has been answered, but I think a few comments are in order: 1) Read this, everyone new to Python should: http://python.net/crew/mwh/hacks/objectthink.html 2) > The only object in python with this behavior are the numeric object (Numeric, numarray or numpy) Not the case (see the above reference). Num* arrays are different than the standard objects in that slicing returns views on data of the array, but all mutable types will behave the same way in your code:
def test(l): ... l *= 3 ... print l [3, 3, 3] test(l) print l [3, 3, 3, 3, 3, 3, 3, 3, 3]
As Travis said, in some languages, the question is "copy or reference?" (and Fortran is always reference, IIRC), in Python, the question is "mutable or immutable?". Immutable objects can not be effected when passed into function, mutable objects can. Using the same test function above:
i = 5 test(5) i 5
integers are immutable, so i was not changed (more accurately, the object bound to i was not changed). Compounding the confusion, is this: the *=, etc operators mean: "mutate the object in place if possible, otherwise return a new object". This is confusing as that means that some objects (ndarrays, list), will get changed by a function like that, and others (ints, floats, tuples) will not. Personally, I would be happier if +=, etc. meant "mutate the object in place if possible, otherwise raise an exception", but then you couldn't do i = 0 i += 1 which is probably the most common use. I think the mistake arose from trying to solve two totally different problems at once: numpy users and the like wanted a clean and compact way to mutate in place. Lots of others (particularly those coming from the C family of languages) wanted a quick and easy notation for "increment this value". Since python numbers are not mutable, these CAN'T be the same thing, so using the same notation for both causes confusion. Of course, you can now use numpy rank zero arrays almost like mutable numbers:
s = N.array(5) test(s) s array(15)
By the way, there are times when I think mutable scalars would be handy. rank-zero arrays almost fit the bill, but I can't see a way to directly re-set their value, and they don't seem to take precedence in operations with other numbers:
s = N.array(5) type(s) <type 'numpy.ndarray'>
s2 = 4 * s type(s2) <type 'numpy.int32'> # so I got a numpy scalar back instead of a rank-zero array
However:
s = N.array((5,6)) type(s) <type 'numpy.ndarray'>
s2 = 4 * s type(s2) <type 'numpy.ndarray'>
This stayed an array, as, of course, it would have to! I now the whole "how the heck should a rank-zero array" behave? has been discussed a lot, but I still wonder if this is how it should be. Maybe having a whole new object that explicitly defined as a mutable scalar would be the way to do it. It would probably have less overhead than a rank-zero array as well. -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov
participants (5)
-
Christopher Barker -
humufr@yahoo.fr -
Pierre GM -
Robert Kern -
Travis Oliphant