The rules followed by NumPy when performing binary operations on arrays mirror those used by Python in general. Operations between numeric and non-numeric types are not allowed (e.g. an array of characters can't be added to an array of numbers), and operations between mixed number types (e.g. floats and integers, floats and omplex numbers, or in the case of NumPy, operations between any two arrays with different numeric typecodes) first perform a coercion of the 'smaller' numeric type to the type of the `larger' numeric type. Finally, when scalars and arrays are operated on together, the scalar is converted to a rank-0 array first. Thus, adding a "small" integer to a "large" floating point array is equivalent to first casting the integer "up" to the typecode of the array:
array([ 12. , 12.1, 12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9])
The automatic coercions are described in Figure 1. Avoiding upcasting is discussed in Saving space.

One more array constructor is the asarray() function. It is used if you want to have an array of a specific typecode and you don't know what typecode array you have (for example, in a generic function which can operate on all kinds of arrays, but needs them to be converted to complex arrays). If the array it gets as an argument is of the right typecode, it will get sent back unchanged. If the array is not of the right typecode, each element of the new array will be the result of the coercion to the new type of the old elements. asarray() will refuse to operate if there might be loss of information -- in other words, asarray() only casts 'up'.
asarray is also used when you have a function that operates on arrays, but you want to allow people to call it with an arbitrary python sequence object. This gives your function a behavior similar to that of most of the builtin functions that operate on arrays.
The typecodes identifiers ( Float0 , etc.) have as values single-character strings. The mapping between typecode and character strings is machine dependent. An example of the correspondences between typecode characters and the typecode identifiers for 32-bit architectures are shown in Table 3-X.
When dealing with very large arrays of floats and if precision is not important (or arrays of small integers), then it may be worthwhile to cast the arrays to "small" typecodes, such as Int8 , Int16 or Float32 . As the standard Python integers and floats correspond to the typecodes Int32 and Float64 , using them in apparently "innocent" ways will result in up-casting, which may null the benefit of the use of small typecode arrays. For example:
'f' # a.k.a. Float32 on a Pentium
>>> mylargearray = mylargearray + 1 # 1 is an Int64 on a Pentium
>>> mylargearray.typecode() # see Fig. 1 for explanation.
Note that the sizes returned by the itemsize() method are expressed in bytes.
Numeric arrays can be created using an optional, keyworded argument to the constructor, savespace. If savespace is set to 1, Numeric will attempt to avoid the silent upcasting behavior. The status of an array can be queried with the spacesaver() method. If x.spacesaver() is true, x has its space-saving flag set. The flag can be set with the savespace method: x.savespace(1) to set it, x.savespace(0) to clear it.