Numbering an array of errors or functions (catsing to int behind the scenes)?

I noticed strange behavior of Numpy / Scipy arrays today. It looks like adding an array cell with an integer inside to a float can have two different results depending on the variable the result is assigned to. Instead of lengthy explanations below, I present the code:

import scipy as sp
array_int = sp.array([[0], [0]])
float_operand = 0.1
print array_int[0, 0] + float_operand #gives 0.1

      

But

import scipy as sp
array_int = sp.array([[0], [0]])
float_operand = 0.1
array_int[0, 0] = array_int[0, 0] + float_operand 
print array_int[0, 0] #gives 0

      

I could figure out if this behavior was inherited from Python, but:

In contrast to the behavior of "naked" Python (2.7):

integer_for_sure = int(0) 
integer_for_sure = integer_for_sure + 0.1
print integer_for_sure #gives 0.1 as expected

      

Is such a feature documented? Has anyone encountered this before?

+3


source to share


2 answers


Henry Cater explained it well enough. I would add just one technical detail.

Unlike normal assignment, which simply returns integer_for_sure

for a reference to the object float

that is obtained from integer_for_sure + 0.1

, thereby changing the type of the variable, assigning to array elements such as

array_int[0, 0] = array_int[0, 0] + float_operand

      

actually syntactic sugar for more verbose

array_int.__setitem__((0,0), array_int.__getitem__((0,0)) + float_operand)

      

(this applies to old style classes, it is slightly different for new style classes, but the idea remains the same)

The method __setitem__

for each array type executes the type of its value argument for the array type. The actual C code that implements the assignment is ugly and includes a custom preprocessor.



On the other hand

print array_int[0, 0] + float_operand

      

is an

print array_int.__getitem__((0,0)) + float_operand

      

i.e. it extracts an integer value from array_int

, sums it up with float_operand

, and the resulting object float

is passed to print

. There is array_int[0, 0]

no intermediate assignment between and an intermediate assignment, so there is no typecast.

+3


source


This is not "Python-inherited" behavior - as you can see, adding a float to an int in pure Python produces a float result. Rather, you can think of this behavior as "inherited from C." Unlike Python lists, numpy arrays have solid element types . The array constructor includes an optional keyword argument that references this:

dtype : data type, optional

The required data type for the array. If not specified, the type will be determined as the minimum type required to store objects in sequence. This argument can only be used for "upscaling".

My accent. When you create an array with np.array([[0], [0]])

, you end up with a two-dimensional array of integers because an integer is the smallest data type it can hold 0

. Once an integer array is created, it can only contain integers. If you try to insert a float, it will be cast to an integer, as you noticed to be placed in an array.




If you want to keep the floats in the array after all, you need to initialize your array as a float array ('upcast' it). This can be achieved with the argument dtype

mentioned above, or simply by putting the float value in the initial array (for example, 0.0

instead of integers 0

).

import scipy as sp
array_int = sp.array([[0], [0]])
array_float = sp.array([[0.0], [0]])  # Note the extra .0 to make one element a float

array_int[0, 0] = array_int[0, 0] + 0.1
print array_int[0, 0] # 0

array_float[0, 0] = array_float[0, 0] + 0.1
print array_float[0, 0] # 0.1

      

+3


source







All Articles