Mechanism for Passing Parameters
- All scalar values are passed to and from Python by value, meaning a copy of the variable is made, and changes to the variable on one side will not affect the other side's value.
- String arrays, lists, tuples, and dictionaries are passed to and from by value.
- Numeric arrays are passed by reference when they are used as arguments or keywords to Python methods.
- Numeric arrays are passed by value when they are passed from IDL to the Python __main__ level and when Python returns a result to IDL. In other words, a copy of the entire array is made. This is due to two reasons. First, unlike Python, IDL has no concept of slices (multiple views into the same array), and could become confused if multiple references to the same array were returned. Second, Python has no simple way to notify when all references to a variable are gone, and therefore IDL does not know when it is safe to delete a variable.
Datatype Conversion
When variables are passed from IDL to Python or Python to IDL (as arguments, keywords, or __main__ variables), the following datatype conversions take place in both directions:
IDL Datatype
|
Python Type
|
!NULL (0) |
None |
Byte (1) |
numpy.uint8 |
Int (2) |
numpy.int16 |
Long (3) |
numpy.int32 |
Float (4) |
numpy.float32 |
Double (5) |
numpy.float64, float
|
Complex (6) |
numpy.complex64 |
String (7) |
str, unicode |
Structure (8) |
see tables below
|
Double Complex (9)
|
numpy.complex128
|
Pointer (10) |
not allowed
|
Objref (11) |
see tables below
|
Uint (12) |
numpy.uint16 |
Ulong (13) |
numpy.uint32 |
Long64 (14) |
numpy.int64 |
Ulong64 (15) |
numpy.uint64 |
The following datatypes are used when converting from IDL to Python:
IDL Datatype
|
Python Type
|
Structure (8) |
collections.OrderedDict
|
String array |
list |
List object
|
list |
Hash, Dictionary object
|
dict |
OrderedHash object
|
collections.OrderedDict
|
IDL PYTHON object
|
corresponding Python object
|
Other IDL class |
Python idlpy.IDL object
|
The following datatypes are used when converting from Python to IDL:
Python Type
|
IDL Type
|
bool, numpy.bool_
|
Byte (1), with boolean flag
|
int, long |
Long (3) or Long64 (14), depending upon value
|
float |
Double (5) |
complex |
Double Complex (9)
|
bytes, bytearray
|
String (7) |
unicode |
String (7) |
numpy string/unicode array
|
String array |
list |
List object
|
dict |
Hash object
|
collections.OrderedDict
|
OrderedHash object
|
tuple |
List object
|
other Python object
|
IDL PYTHON object that wraps the Python object
|
Python IDL object
|
corresponding IDL PYTHON object
|
Array Dimensions and Array Majority
In IDL the data within a multi-dimensional array is organized as "column major," while in Python the data is organized as "row major."
Column Major Versus Row Major
In IDL, for a two-dimensional array the first dimension represents the "columns" of that array, while the second dimension represents the "rows". In terms of memory layout, the first dimension varies the "fastest", and has a stride equal to the size of the datatype in bytes. The second dimension varies the "slowest" and has a stride equal to the number of columns multiplied by the datatype size in bytes. For example, for a 16-bit integer array each column is separated by two bytes while each row is separated by 6 bytes:
IDL> x = INDGEN(3,2)+1
IDL> PRINT, x
1 2 3
4 5 6
IDL> PRINT, x[2,1]
6
IDL> PRINT, BYTE(x, 0, 6*2)
1 0 2 0 3 0 4 0 5 0 6 0
In Python, for a two-dimensional array the first dimension represents the "rows" of that array, while the second dimension represents the "columns". In terms of memory layout, the first dimension varies the "slowest", and has a stride equal to the number of columns multiplied by the datatype size in bytes. The second dimension varies the "fastest" and has a stride equal to the size of the datatype in bytes. For example, for a 16-bit integer array each column is separated by two bytes while each row is separated by 6 bytes:
>>> import numpy as np
>>> x = np.array([[1, 2, 3], [4, 5, 6]], np.int16)
>>> x.shape
(2L, 3L)
>>> x.strides
(6L, 2L)
>>> x[1,2] # value in row 1, column 2
6
>>> x.tobytes()
'\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00'
Notice that in both Python and IDL the bytes are organized the same in memory; it is only the way that the dimensions are reported and the indexing order that is different.
Array Conversion
When IDL passes an array to Python, or when Python passes an array back to IDL, the bytes within the data array remain unchanged. Instead, the order of the dimensions is reversed. For example, if we create an array in IDL that has dimensions [3, 640, 480], then in Python the dimensions will be reported as [480, 640, 3]:
IDL> x = BYTARR(3, 640, 480)
IDL> HELP, x
X BYTE = Array[3, 640, 480]
IDL> Python.x = x
IDL> Python.Run('x.shape')
(480, 640, 3)
In most cases this will be the desired behavior. However, in some cases you may need to transpose your actual data values. For example, you might read in the data from a file in IDL, and then run the data through a Python algorithm that expects a certain order. In IDL you can use the TRANSPOSE function to re-order the values within an array before sending it to Python, while in Python you can use numpy.transpose.
Version History
8.5 |
Introduced |
8.6 |
Handle numpy string/unicode arrays; handle IDL structures, OrderedHash; handle Python collections.OrderedDict
|
8.6.1 |
For variables passed from Python to IDL, change from pass-by-reference to pass-by-value. |
See Also
Python Bridge