Bridges > Python Bridge > IDL to Python

# IDL to Python Bridge

The PYTHON class provides a bridge from IDL to Python. The class contains a set of static methods that allow you to initialize and interact with the Python interpreter. In addition, each object passed back from Python is wrapped in an instance of the PYTHON class; you can then call methods on the underlying Python object, or set and retrieve attributes on the object. The PYTHON class also makes use of operator overloading, so that many of the built-in IDL routines and mathematical operations will work seamlessly with the wrapped Python object.

Note: See Python Bridge for installation instructions.

### Methods and Additional Information

- PYTHON( )
- Python::Import
- Python::Run
- Python::Wrap
- Calling Python Methods
- Get and Set Python Attributes
- Get the List of Methods and Attributes
- Case Sensitivity
- Built-in Functions
- Operator Overloading and Magic Methods
- Accessing Python List, Tuple, Dictionary, or Array Elements
- Using Foreach to Iterate
- Using Python Callable Objects
- Passing Variables to the Main Python Level
- Mechanism for Passing Parameters
- Datatype Conversion
- Array Dimensions and Array Majority
- Python Command Mode

- Information about Python Objects

## Examples

Call Python methods directly from IDL code, as if it was an IDL object:

IDL> ran = Python.Import('numpy.random')

IDL> arr = ran.rand(100) ; call "rand" method

IDL> plt = Python.Import('matplotlib.pyplot')

IDL> p = plt.plot(arr) ; call "plot", pass an array

IDL> void = plt.show(block=0) ; pass keyword

Execute the same commands, but called directly within the Python interpreter:

IDL> Python.Run('import matplotlib.pyplot as plt')

IDL> Python.Run('import numpy.random as ran')

IDL> Python.Run('arr = ran.rand(100)')

IDL> Python.Run('p = plt.plot(arr)')

IDL> Python.Run('plt.show()')

As a shortcut for Python.Run, you can type three ">>>" characters before each statement:

IDL> >>>import matplotlib.pyplot as plt

IDL> >>>import numpy.random as ran

IDL> >>>arr = ran.rand(100)

IDL> >>>p = plt.plot(arr)

IDL> >>>plt.show()

You can also type three ">>>" characters and press the Enter key to enter Python Command Mode:

IDL> >>>

>>> import matplotlib.pyplot as plt

>>> import numpy.random as ran

>>> arr = ran.rand(100)

>>> p = plt.plot(arr)

>>> plt.show()

>>>

IDL>

At the end, press press the Enter key to re-enter the normal IDL command mode.

# Python Class

## Syntax

Result = PYTHON( [PyID])

Note: You should not need to directly call the PYTHON function. Instead, use Python.Import() or Python.Wrap() to return references to Python objects. This syntax is provided here merely for completeness.

## Return Value

Returns a reference to a newly-created PYTHON object.

## Arguments

### PyID

An integer giving the identifier of the object within the Python interpreter. If PyID is not supplied then a reference is returned to the Python `__main__` object.

## Keywords

None

# Python::Import

The Python::Import static method imports a module into the Python interpreter. This also starts the Python interpreter if it has not yet been started.

## Syntax

Result = Python.Import( Module )

or

Python.Import, Module

## Return Value

If Python.Import is called as a function, then the result is a PYTHON object that wraps the Python module. You can then call functions and get or set attributes using the "dot" notation on that object. This is equivalent to the Python statement `import Module as` Result.

If Python.Import is called as a procedure, then all of the functions and attributes within Module are imported into the Python `__main__`. This is equivalent to the Python statement `from Module import *`. In this case all of the functions and attributes will be available from the static Python class.

Note: In Python, it is generally considered bad practice to use `from module import *`, as this pollutes the Python `__main__` namespace and can lead to name conflicts. For this reason you should almost always use the Python.Import function method, and access all of your methods and attributes off of the returned PYTHON object.

## Arguments

### Module

A string giving the name of the Python module to import. To import a module within a package of modules you can use dots to separate the names, such as `module.submodule.subsubmodule`.

## Keywords

None

# Python::Run

The Python::Run static method executes Python commands within the Python interpreter. This also starts the Python interpreter if it has not yet been started.

## Examples

Execute some arbitrary Python code and print the result:

IDL> PRINT, Python.Run('[x*x for x in range(1,11)]')

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Construct a Python "generator", retrieve the generator, and print the values using `foreach`:

IDL> Python.Run, 'mygen = (x*x for x in range(1,11))'

IDL> mygen = Python.mygen

IDL> HELP, mygen

MYGEN PYTHON <ID=3618> <class 'generator'>

IDL> foreach val, mygen do PRINT, val

1

4

...

100

Create a new Python function using a multi-line statement, then use it:

IDL> Python.Run, "def hello(x):\n" + $

" 'Prints out a friendly message'\n" + $

" return 'Hello, ' + x + '!'"

IDL> Python.Help(Python.hello)

Python Library Documentation: function hello in module_main_

hello(x)

Prints out a friendly message

IDL> PRINT, Python.hello("World")

Hello, World!

## Syntax

Result = Python.Run( Command )

or

Python.Run, Command

## Return Value

If Python.Run is called as a function method, then the result is an IDL scalar string or a string array containing the Python output from executing the command. If the command produced no output then an empty string is returned.

If Python.Run is called as a procedure method, then the Python output is redirected to the IDL console.

## Arguments

### Command

An IDL string or string array containing the Python statements to execute in the Python interpreter. If Command is a string array then IDL will send each element to Python as a separate statement. You can also send a multi-line statement (such as a function definition) by using a single IDL string and separating the lines with the "\n" escape code.

## Keywords

None.

# Python::Wrap

The Python::Wrap static method converts an IDL variable to a Python object and returns a wrapped PYTHON object. This also starts the Python interpreter if it has not yet been started.

## Examples

Wrap an IDL floating-point array and call a Python method on it:

IDL> a = Python.Wrap(RANDOMU(seed,10000))

IDL> HELP, a

A PYTHON <ID=399043> <class 'numpy.ndarray'>

IDL> PRINT, a.mean() ; call a numpy.ndarray method

0.497082

## Syntax

Result = Python.Wrap( Value )

## Return Value

The result is a PYTHON object containing the IDL data. You can then call functions and get or set attributes using the "dot" notation on that object.

## Arguments

### Value

An IDL variable of any type except pointer.

## Keywords

None

# Calling Python Methods

Once you have a PYTHON object (say from calling Python::Import), you can call Python methods on that object by using the "dot" notation. Arguments and keywords can be passed to the method, just like calling an IDL method. For example:

; Define some IDL variables

labels = ['Baltam', 'Python', 'IDL', 'Other']

sizes = [20, 30, 40, 10]

colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral']

explode = [0, 0, 0.1, 0] ; "explode" the 3rd slice

; Import some Python modules

pyplot = Python.Import('matplotlib.pyplot')

; Call methods on the Python modules

pie = pyplot.pie(sizes, explode=explode, $

labels=labels, colors=colors, $

autopct='%1.1f%%', /shadow, startangle=90)

void = pyplot.axis('equal')

void = pyplot.savefig("myplot.png", dpi = 96)

void = pyplot.show()

This creates the figure shown to the right. Note that when calling methods, you can pass in IDL variables using standard syntax for arguments and keywords.

# Get and Set Python Attributes

Once you have a PYTHON object (say from calling Python::Import or Python::Wrap), you can retrieve or set attributes on that object by using the "dot" notation. As an example, many Python objects have a `__doc__` attribute that contains a brief description of the class. We can access this using the following code:

IDL> rand = Python.Import('numpy.random')

IDL> rand.__doc__

========================

Random Number Generation

========================

...

You can also set attribute values using the "dot" notation. For example, we can define our own Python class, and then get and set attributes on an instance of that class:

Python.Run, "class MyClass:\n" + $

" myattr = 'world?'\n" + $

" def hello():\n" + $

" 'Prints out a friendly message'\n" + $

" return 'Hello, ' + self.myattr

; Create an instance and retrieve the Python variable.

Python.Run, 'myvar = MyClass()'

myvar = Python.myvar

; Now retrieve the attribute value and then modify it.

PRINT, myvar.myattr

myvar.myattr = 'World!'

PRINT, myvar.hello()

IDL prints:

world?

Hello, World!

# Get the List of Methods and Attributes

You can call the Python built-in `dir` method to retrieve an IDL list containing the available methods and attributes. For example:

IDL> pyplot = Python.Import('matplotlib.pyplot')

IDL> attr = Python.dir(pyplot)

IDL> attr.ToArray()

Annotation

Arrow

Artist

...

ylim

yscale

yticks

# Case Sensitivity

IDL variable and method names are case insensitive while Python names are case sensitive. When you call a Python method such as the `savefig` method on the `matplotlib.pyplot` module, the Python bridge first looks for a lowercase method with that name. If it does not find a match, the bridge then uses the internal dictionary of methods and attributes (`__dict__`) to try to find a case-insensitive match. The first match is assumed to be correct.

If your module happens to have two methods or attributes with the same name that differ only in case, you can use the built-in `Python.getattr` to retrieve the correct one.

# Built-in Functions

Python has a number of "builtin" methods such as `abs()`, `cmp()`, `dir()`, `map()`, or `reduce()`. These can be invoked as static methods on the Python class. For example:

IDL> a = -5

IDL> Python.abs(a)

5

IDL> Python.dir()

[

"_builtins_",

"_doc_",

"_name_",

"_package_",

"mygen",

"myvar"

]

Here is a partial list of built-in functions that you may find useful:

#### Python.dir( [object] )

With no argument, return the list of names in the current local scope. With a Python object, return a list of valid attributes for that object.

#### Python.getattr( object, attr [, default] )

Retrieve the attribute attr from the Python object. attr must be a string. If the attribute does not exist then default is returned if provided, otherwise an error is thrown.

#### Python.hasattr( object, attr )

Return 1 (true) if the object has the attribute attr, or 0 (false) otherwise.

#### Python.help( object )

Returns a string array containing the help documentation for the specified object.

#### Python.id( object )

Returns an integer giving the Python identifier number.

#### Python.isinstance( object, classinfo )

Returns 1 (true) if the Python object is an instance of the classinfo Python object, or 0 (false) otherwise.

#### Python.len( object )

Returns an integer giving the number of items within an object.

#### Python.repr( object )

Returns the string representation of the object. This is the same as what IDL implied print will return.

#### Python.setattr(object, attr, value)

Set the attribute attr on the Python object to the provided value. attr must be a string.

#### Python.str( object )

Returns the string representation of the object. This is the same as what normal IDL print will return.

#### Python.vars( object )

Returns an IDL hash containing the `__dict__` attribute for the object. The `__dict__` attribute contains all of the attributes and methods of the object.

# Operator Overloading and Magic Methods

In IDL, PYTHON objects can be used in most mathematical, logical, and bitwise expressions. When a PYTHON object is used in an expression, any "normal" IDL variables (such as integers, floats, or strings) are first converted to PYTHON objects. Then, a call is made to the appropriate Python "magic method" and the result is returned. The result is converted back to a normal IDL variable if possible, otherwise a PYTHON object is returned.

The following table lists the Python magic method that is invoked for each IDL operator:

Operator | IDL Syntax | Python Call
--- | --- | ---
Plus | a + b | __add__
Minus | a – b | __sub__
Asterisk | a * b | __mul__
Slash | a / b | __div__
MinusUnary | –a | __neg__
Caret | a^b | __pow__
Modulus | a mod b | __mod__
Equal | a EQ b | __eq__
Not equal | a NE b | __ne__
Greater than or equal | a GE b | __ge__
Less than or equal | a LE b | __le__
Greater than | a GT b | __gt__
Less than | a LT b | __lt__
Bitwise and | a AND b | __and__
Bitwise or | a OR b | __or__
Bitwise xor | a XOR b | __xor__
Bitwise not | NOT b | __invert__
Is true | if (a) | bool( )
Logical negation | ~a | ~bool(a)

# Accessing Python List, Tuple, Dictionary, or Array Elements

In many cases, you can access elements of a PYTHON object using standard IDL array syntax, as if the object were a "normal" IDL array. When you access a Python object and retrieve an element or a set of elements, IDL will convert the result back into a "normal" IDL variable. Here are some examples:

#### Using a Python List or Tuple

IDL> var = Python.Wrap(List(3.14, 1234, 'hello'))

IDL> HELP, var

VAR PYTHON <ID=202> <class 'list'>

IDL> PRINT, var[2]

hello

IDL> var[0] = 3.14159

IDL> PRINT, var

[3.1415901, 1234, 'hello']

#### Using a Python Dictionary

IDL> var = Python.Wrap(HASH('Mercury', 1, 'Venus', 2, 'Earth', 3))

IDL> HELP, var

VAR PYTHON <ID=248> <class 'dict'>

IDL> PRINT, var['Venus']

2

IDL> var['Mars'] = 4

IDL> PRINT, var

{'Mercury': 1, 'Earth': 3, 'Mars': 4, 'Venus': 2}

#### Using a Python Array

IDL> var = Python.Wrap(INDGEN(10))

IDL> HELP, var

VAR PYTHON <ID=258> <class 'numpy.ndarray'>

IDL> PRINT, var[3:5]

3 4 5

IDL> var[-2:*] = -1

IDL> PRINT, var

[ 0 1 2 3 4 5 6 7 -1 -1]

# Using Foreach to Iterate

You can use the IDL FOREACH statement on a Python `list`, `tuple`, `dict`, `ndarray`, or any other Python class that implements the iterator protocol. For example:

IDL> a = Python.Wrap(LIST('a',2,'c',3.14))

IDL> foreach value,a,index do print, value, index

a 0

2 1

c 2

3.14000 3

For Python `dict` (or other classes with an iterator) the FOREACH "index" variable (the third argument) will be set equal to the Python iterator. You should avoid modifying this variable. For example:

IDL> a = Python.Wrap(HASH('Mercury',1,'Venus',2,'Earth',3))

IDL> HELP,a

A PYTHON <ID=71> <class 'dict'>

IDL> foreach planet,a,index do HELP,planet,index

PLANET STRING = 'Venus'

INDEX PYTHON <ID=74> <class 'dict_keyiterator'>

PLANET STRING = 'Mercury'

INDEX PYTHON <ID=74> <class 'dict_keyiterator'>

PLANET STRING = 'Earth'

INDEX PYTHON <ID=74> <class 'dict_keyiterator'>

# Using Python Callable Objects

In most cases you invoke methods by using the "dot" notation on a Python module or object. For example:

IDL> randomModule = Python.Import("numpy.random")

IDL> x = randomModule.rand(50) ; invoke the "rand" method

IDL> HELP, x

X DOUBLE = Array[50]

However, in certain cases you may end up with a reference to an actual Python method object. For example, if you used `Python.getattr` to retrieve the method object by name:

IDL> randMethod = Python.getattr(randomModule, 'rand')

IDL> HELP, randMethod

RANDMETHOD PYTHON <ID=2252> <class 'builtin_function_or_method'>

IDL> Python.callable(randMethod)

1

In these cases, you can call the method using parentheses:

IDL> x = randMethod(50) ; invoke the "rand" method

IDL> HELP, x

X DOUBLE = Array[50]

You could also use the __call__ magic method to invoke the method:

IDL> x = randMethod.__call__(50) ; invoke the "rand" method

# Passing Variables to the Main Python Level

Normally, you will pass IDL variables into Python method calls as input arguments or keywords, and receive the result back as an IDL variable. However, if you use the `Python.Run` method, you may want to pass variables to or from Python directly. To do this, you can use the standard IDL "dot" notation on the PYTHON static class. For example:

#### Set a Python variable

IDL> Python.myvar = FINDGEN(10) ; pass by value (makes a copy)

IDL> Python.Run('myvar')

'array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32)'

#### Retrieve a Python variable

IDL> myvar2 = Python.myvar ; pass by reference

IDL> HELP, myvar2

MYVAR2 FLOAT = Array[10]

Note: All variables that are passed to Python will be given a lowercase name, regardless of the original case. When retrieving variables from Python, the lowercase version will be tried first. If it does not find a match, then the bridge uses Python's internal dictionary of attributes (`__dict__`) to try to find a case-insensitive match. The first match is assumed to be correct. If you happen to have two variables with the same name that differ only in case, you can use the built-in `Python.getattr` to retrieve the correct one. For example:

IDL> void = Python.Run('var = 1')

IDL> void = Python.Run('Var = 2')

IDL> PRINT, Python.var ; retrieves the first variable

1

IDL> ; Retrieve the second variable by name from Python __main__

IDL> PRINT, Python.getattr(Python(), 'Var')

2

# Mechanism for Passing Parameters

- All scalar values are passed to and from Python by value — in other words, 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 reference when they are passed back from Python `__main__` variables to IDL. Changing one of the elements in either IDL or Python will change the corresponding element on the other side.
- Numeric arrays are passed by value when they are passed from IDL to the Python `__main__` level. In other words, a copy of the entire array is made. This is because the IDL code could delete the variable, but we have no way of knowing if the variable is still in use on the Python side since Python has no simple way to notify when all references to a variable are gone.

# 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) | dict
List object | list
Hash, Dictionary, OrderedHash object | dict
IDL PYTHON object | corresponding Python object
Other IDL class | not allowed

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)
list | List object
tuple | List object
dict | Hash 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 ; 3 columns by 2 rows

IDL> PRINT, x

1 2 3

4 5 6

IDL> PRINT, x[2,1] ; value in column 2, row 1

6

IDL> PRINT, BYTE(x, 0, 6*2) ; print the byte representation

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 ; transfer array to Python

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`.

# Python Command Mode

In most cases you will want to interact with Python by using `Python.Import` to retrieve a module, and then calling methods on the returned PYTHON object. However, you can also execute Python statements directly within the Python interpreter using the `Python.Run` method. As a shortcut to typing Python.Run, you can also type three ">>>" characters:

IDL> >>>import matplotlib.pyplot as plt

IDL> >>>import numpy.random as ran

IDL> >>>arr = ran.rand(100)

IDL> >>>p = plt.plot(arr)

IDL> >>>plt.show()

Note that you need to type three ">>>" characters before each Python statement.

As an alternative, you can type three ">>>" characters and press press the Enter key to enter "Python Command Mode":

IDL> >>>

>>> import matplotlib.pyplot as plt

>>> import numpy.random as ran

>>> arr = ran.rand(100)

>>> p = plt.plot(arr)

>>> plt.show()

>>>

At the end, press press the Enter key to re-enter the normal IDL command mode.

Be aware that there are a few limitations in Python Command Mode:

- Unlike the regular Python console, you cannot enter a multi-line construct on separate lines. If you want to enter a multi-statement construct (such as a function definition), all of the statements must be on the same line, separated by semicolons. For example:

>>> def hello(x): print(x); return 'Hello'

- Any variables or objects created using `Python.Run` or Python Command Mode will exist only within the Python interpreter. To work with these objects within IDL, you will need to retrieve a reference. For example:

IDL> >>>

>>> import matplotlib.pyplot as plt

>>> import numpy.random as ran

>>> arr = ran.rand(100)

>>>

IDL> myarr = Python.arr ; retrieve the array from Python

# Information about Python Objects

#### N_ELEMENTS, DIM, LENGTH, NDIM

The N_ELEMENTS function and the LENGTH variable attribute return the number of elements within the Python object. For Python `ndarray` objects, the `shape` attribute is used to compute the total number of elements. For all other Python objects, IDL calls `Python.len()` and returns the result.

The DIM variable attribute returns a scalar or array giving the dimensions of the object. For Python `ndarray` objects, DIM is set equal to the `shape` attribute in reverse order (since Python is "row major"). For all other Python objects, IDL calls `Python.len()` on the object and returns the result.

The NDIM variable attribute returns an integer giving the number of dimensions of the object. For Python `ndarray` objects, NDIM is set equal to the number of elements in the `shape` attribute. For all other Python objects, IDL returns NDIM=1 for Python objects that have multiple items (such as lists, tuples, or dicts), or 0 for scalar Python objects.

#### HELP

The HELP procedure provides a brief description of the PYTHON object:

IDL> np = Python.Import('numpy')

IDL> HELP, np

NP PYTHON <ID=327> <class 'module'>

IDL> HELP, np.ndarray

<Expression> PYTHON <ID=330> <class 'type'>

If you want more detailed information, you may want to call `Python.help()` on your object.

#### ISA

The IDL ISA function uses the following rules:

- ISA(pyObj, 'OBJREF') always returns true
- ISA(pyObj, /ARRAY) returns true if pyObj is considered to be an "array", or false otherwise. See N_ELEMENTS above for the rules.
- ISA(pyObj, /SCALAR) returns true if pyObj is considered to be a "scalar", or false otherwise. See N_ELEMENTS above for the rules.

All other ISA keywords will return false.

#### TYPECODE, TNAME, TYPENAME

PYTHON objects always return TYPECODE=11, TNAME='OBJREF', and TYPENAME='PYTHON'.

#### PRINT and Implied Print

The PRINT procedure will call `Python.str()` on the object, while using Implied Print will call `Python.repr()`. For example:

IDL> arr = Python.Wrap(INDGEN(5))

IDL> PRINT, arr

[0 1 2 3 4]

IDL> arr

array([0, 1, 2, 3, 4], dtype=int16)

## Version History

8.5 | Introduced

## See Also

!NULL, HASH, LIST, Python to IDL Bridge