---
title: "Python"
language: "en"
type: "External Evaluation System"
summary: "Python (External Evaluation System)"
canonical_url: "https://reference.wolfram.com/language/ref/externalevaluationsystem/Python.html"
source: "Wolfram Language Documentation"
related_guides: 
  - 
    title: "External Interpreted Language Interfaces"
    link: "https://reference.wolfram.com/language/guide/ExternalInterpretedLanguageInterfaces.en.md"
  - 
    title: "External Language Interfaces"
    link: "https://reference.wolfram.com/language/guide/ExternalLanguageInterfaces.en.md"
  - 
    title: "Wolfram Client Library for Python"
    link: "https://reference.wolfram.com/language/guide/WolframClientLibraryForPython.en.md"
related_workflows: 
  - 
    title: "Configure Python for ExternalEvaluate"
    link: "https://reference.wolfram.com/language/workflow/ConfigurePythonForExternalEvaluate.en.md"
---
[EXPERIMENTAL]

# "Python" (External Evaluation System)	[image]

## Details

Python 3.4+ is supported.

In most cases, the Wolfram Language will automatically provision one Python environment, and no manual user configuration is required. For advanced configuration, follow the instructions from the [Configure Python for ExternalEvaluate](https://reference.wolfram.com/language/workflow/ConfigurePythonForExternalEvaluate.en.md) workflow.

---

ExternalEvaluate Usage

``ExternalEvaluate["Python", code] ``executes Python code and returns the results as a Wolfram Language expression.

``ExternalEvaluate[{"Python", "Evaluator" -> evaluator}, code] ``executes the code using a Python environment specified by ``evaluator``.

The possible values for ``evaluator`` in ``ExternalEvaluate[{"Python", "Evaluator" -> evaluator}, …] ``include:

|                |                                     |
| -------------- | ----------------------------------- |
| "path"         | the location of a Python executable |
| File["path"]   | the location of a Python executable |
| Association[…] | a virtual environment specification |

In ``ExternalEvaluate[{"Python", "Evaluator" -> assoc}, …]``, possible elements of ``assoc`` include:

|                 |           |                                                                                         |
| --------------- | --------- | --------------------------------------------------------------------------------------- |
| "Dependencies"  | {}        | packages automatically installed using pip                                              |
| "EnvironmentID" | Automatic | name of the virtual environment directory to be created                                 |
| "PythonRuntime" | Automatic | specification of the Python runtime to be used, like "3.11" or File["/usr/bin/python3"] |
| "BaseDirectory" | Automatic | the directory of the created virtual environment                                        |

Possible settings for ``"type"`` in ``ExternalEvaluate["Python" -> "type", code]`` include:

|                  |                                                      |
| ---------------- | ---------------------------------------------------- |
| "Expression"     | attempt to convert to a Wolfram Language expression  |
| "String"         | give the raw string output by the external evaluator |
| "ExternalObject" | return the result as ExternalObject                  |

Data Types

Not all Python built-in types are supported. The supported Python types are:

|               |               |                                           |
| ------------- | ------------- | ----------------------------------------- |
| bool          | True \| False | Boolean values                            |
| array         | NumericArray  | arrays (from the NumPy library)           |
| bytearray     | ByteArray     | sequence of integers 0-255                |
| bytes         | ByteArray     | immutable sequence of integers 0-255      |
| complex       | Complex       | complex number                            |
| date          | DateObject    | specific calendar date                    |
| datetime      | DateObject    | specific date with time granularity       |
| Decimal       | Real          | arbitrary-precision real number           |
| dictionary    | Association   | association of keys and values            |
| float         | Real          | real-valued number                        |
| Fraction      | Rational      | fraction object from the fractions module |
| frozenset     | List          | unordered immutable set of unique values  |
| Image         | Image         | image (from Python PIL library)           |
| int           | Integer       | arbitrary-sized integer                   |
| list          | List          | sequence of values                        |
| long          | Integer       | arbitrary-sized integer                   |
| None          | Null          | null value                                |
| set           | List          | unordered set of unique values            |
| str           | String        | sequence of character values              |
| tuple         | List          | ordered sequence of values                |
| pyarrow.Table | Tabular       | tabular with rectangular data             |

Any unsupported Python type that is *callable* returns an ``ExternalFunction``; any other unsupported Python type returns an ``ExternalObject``.

The precision of a ``Real`` returned from a ``Decimal`` object is maintained when returned from ``ExternalEvaluate``.

Python ``complex`` types are required to be real, so any ``Complex`` expression returned from ``ExternalEvaluate`` will have real-valued components.

Supported External Operations

``ExternalOperation["Eval", "code"]`` represents an external evaluation of ``"code"``.

``ExternalOperation["Eval", "code", assoc]`` represents an external evaluation of ``"code"`` with parameters given by ``assoc``.

``ExternalOperation["Call", func, arg1, arg2, …]`` calls the function ``func`` with the given arguments ``arg1``, ``arg2``, ``…``.

``ExternalOperation["GetAttribute", obj, "attr"]`` gets the attribute ``"attr"`` of ``obj``.

``ExternalOperation["SetAttribute", obj, "attr", val]`` sets the attribute ``"attr"`` of ``obj`` to the given value ``val``.

``ExternalOperation["GetItem", obj, "item"]`` gets the item ``"item"`` of ``obj``.

``ExternalOperation["SetItem", obj, "item", val]`` sets the item ``"item"`` of ``obj`` to the given value ``val``.

``ExternalOperation["Import", "path"]`` imports the module ``"path"``.

``ExternalOperation["Import", "path", "attr"]`` imports the module ``"path"``, then gets the attribute ``"attr"`` from the module.

``ExternalOperation["Cast", obj, "type"]`` casts ``obj`` to the given ``"type"``.

Usage Notes

String templates (<\*…\*>) can be used to evaluate and insert Wolfram Language expressions into the Python code string.

---

## Examples (59)

### Basic Examples (3)

Evaluate $2+2$ in Python and return the result:

```wl
In[1]:= ExternalEvaluate["Python", "2+2"]

Out[1]= 4
```

Create a list in Python and return the result:

```wl
In[2]:= ExternalEvaluate["Python", "[i**2 for i in range(10)]"]

Out[2]= {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
```

Type > to get a Python code cell that uses ``ExternalEvaluate`` to evaluate:

In[3]:=
import math
[math.sqrt(i) for i in range(10)]

```wl
Out[3]= {0., 1., 1.41421, 1.73205, 2., 2.23607, 2.44949, 2.64575, 2.82843, 3.}
```

Create a list with exponentials and logarithms:

In[4]:= [[i,math.exp(i),math.log(i)] for i in range(1,10)]

```wl
Out[4]= {{1, 2.71828, 0.}, {2, 7.38906, 0.693147}, {3, 20.0855, 1.09861}, {4, 54.5982, 1.38629}, {5, 148.413, 1.60944}, {6, 403.429, 1.79176}, {7, 1096.63, 1.94591}, {8, 2980.96, 2.07944}, {9, 8103.08, 2.19722}}
```

Create a list with the days of the week:

In[5]:=
import calendar
[calendar.day\_name[i] for i in range(7)]

```wl
Out[5]= {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}
```

---

Use the ``File`` wrapper to execute code contained in a file:

```wl
In[1]:= path = Export[CreateFile[], "range(5)", "String"]

Out[1]= "/private/var/folders/r0/42w4s40j08v1h08jdz03mwgw0000gn/T/m000088667091"

In[2]:= ExternalEvaluate["Python", File[path]]

Out[2]= {0, 1, 2, 3, 4}
```

Deploy code using ``CloudDeploy`` and then run the code directly from a ``CloudObject`` :

```wl
In[3]:= cobj = CloudExport["range(5)", "String"]

Out[3]= CloudObject["https://www.wolframcloud.com/obj/247b1e87-ce00-44de-b2de-e989b2553584"]

In[4]:= ExternalEvaluate["Python", cobj]

Out[4]= {0, 1, 2, 3, 4}
```

Use a ``URL`` wrapper to directly run code hosted online:

```wl
In[5]:= addtwo = URL["https://exampledata.wolfram.com/script.py"]

Out[5]= URL["https://exampledata.wolfram.com/script.py"]

In[6]:= ExternalEvaluate["Python", {addtwo, "addtwo(3)"}]

Out[6]=
{ExternalFunction[ExternalSessionObject["physielly-thists-036mi6p3k5oec"], 
 ExternalOperation["GetReference", 4359628112], Association["Arguments" -> {"a"}, 
  "IsModule" -> False, "IsClass" -> False, "IsFunction" -> True, "IsMethod" -> False, 
  "IsCallable" -> True]], 5}
```

---

An ``Association`` can be used to automatically provision a Python virtual environment:

```wl
In[1]:=
session = StartExternalSession[
	{
	"Python", 
	"Evaluator" -> <|
	"Dependencies" -> {"emoji"}, 
	"EnvironmentID" -> "myenv"
	|>
	}
	]

Out[1]= ExternalSessionObject["shoot-stotts-1tgydl0goxaor"]

In[2]:=
ExternalEvaluate[
	session, 
	"import emoji; emoji.emojize('Emojis are :thumbs_up:')"
	]

Out[2]= "Emojis are 👍"
```

The Python virtual environment was created under ``\$UserBaseDirectory`` :

```wl
In[3]:=
ExternalEvaluate[
	session, 
	"import sys; sys.executable"
	]

Out[3]= "/Users/rdv/Library/Wolfram/ApplicationData/ExternalEvaluate/Envs/Python/Cache/archive-v0/iSQP0k9LNKE0BeObaYbKK/bin/python3"
```

### Scope (51)

Evaluate a Boolean statement in Python and return the result:

```wl
In[1]:= ExternalEvaluate["Python", "True and False"]

Out[1]= False
```

---

Create a byte array in Python and return its equivalent in the Wolfram Language:

```wl
In[1]:= ExternalEvaluate["Python", "b'afewbytes'"]

Out[1]= ByteArray[{97, 102, 101, 119, 98, 121, 116, 101, 115}]
```

Another way to work with a byte array in Python:

```wl
In[2]:= ExternalEvaluate["Python", "bytes([42,42,42])"]

Out[2]= ByteArray[{42, 42, 42}]
```

---

Python ``list``, ``tuple``, ``set`` and ``frozenset`` are converted to ``List`` :

```wl
In[1]:= ExternalEvaluate["Python", "(0, 1, 2)"]

Out[1]= {0, 1, 2}

In[2]:= ExternalEvaluate["Python", "[0, 1, 2]"]

Out[2]= {0, 1, 2}

In[3]:= ExternalEvaluate["Python", "set(range(3))"]

Out[3]= {0, 1, 2}

In[4]:= ExternalEvaluate["Python", "frozenset(range(3))"]

Out[4]= {0, 1, 2}
```

Python ``dict`` are converted to ``Association`` :

```wl
In[5]:= ExternalEvaluate["Python", "dict(a = 2, b = 3)"]

Out[5]= <|"a" -> 2, "b" -> 3|>
```

When using a Python higher than 3.7, dictionary keys are ordered, just like ``Association`` :

```wl
In[6]:= ExternalEvaluate["Python", "{i+1: bool(i % 2) for i in range(10)}"]

Out[6]= <|1 -> False, 2 -> True, 3 -> False, 4 -> True, 5 -> False, 6 -> True, 7 -> False, 8 -> True, 9 -> False, 10 -> True|>
```

---

Create a ``Complex`` number in Python and return the result:

```wl
In[1]:= ExternalEvaluate["Python", "complex(1,1)"]

Out[1]= 1.  + 1. I
```

Fractions are automatically converted to ``Rational`` :

```wl
In[2]:= ExternalEvaluate["Python", "from fractions import Fraction; Fraction(2, 3)"]

Out[2]= (2/3)
```

Decimals are converted to ``Real`` :

```wl
In[3]:= ExternalEvaluate["Python", "from decimal import Decimal; Decimal(2.5)"]

Out[3]= 2.500000000000000000000000000
```

---

Fractions are automatically converted to ``Rational`` :

```wl
In[1]:= ExternalEvaluate["Python", "from fractions import Fraction; Fraction(2, 3)"]

Out[1]= (2/3)
```

Decimals are converted to ``Real`` :

```wl
In[2]:= ExternalEvaluate["Python", "from decimal import Decimal; Decimal(2.5)"]

Out[2]= 2.500000000000000000000000000
```

---

Datetime objects are automatically converted:

```wl
In[1]:=
ExternalEvaluate["Python", {
	"import datetime", 
	"datetime.timedelta(days = 3)", 
	"datetime.datetime(2020, 3, 15)", 
	"datetime.date(2077, 12, 13)"
	}]

Out[1]= {Null, Quantity[259200., "Seconds"], DateObject[{2020, 3, 15, 0, 0, 0.}, "Instant", "Gregorian", None], DateObject[{2077, 12, 13}, "Day"]}
```

---

NumPy arrays are automatically converted to ``NumericArray`` :

```wl
In[1]:= ExternalEvaluate["Python", "import numpy; numpy.arange(10)"]

Out[1]=
Failure["PythonError", Association["MessageTemplate" :> "No module named 'numpy'", 
  "MessageParameters" :> Association[], "FailureCode" :> "ModuleNotFoundError", 
  "Traceback" :> OpenerView[{Row[{"ModuleNotFoundError", " ", "No module named 'num ... tem["   1.  import numpy; numpy.arange(10)", 
               Background -> LightYellow]}, Background -> {{GrayLevel[0.95], GrayLevel[1]}}, 
             Frame -> LightGray], "No local variables"}]}, True]}], FontFamily -> "Courier"]}, 
    True]]]
```

---

Pandas DataFrames are automatically converted to ``Dataset`` :

```wl
In[1]:= ExternalEvaluate["Python", "import pandas as pd; d = {'col1': [1, 2], 'col2': [3, 4]}; pd.DataFrame(data=d)"]

Out[1]=
Failure["PythonError", Association["MessageTemplate" :> "No module named 'pandas'", 
  "MessageParameters" :> Association[], "FailureCode" :> "ModuleNotFoundError", 
  "Traceback" :> OpenerView[{Row[{"ModuleNotFoundError", " ", "No module named 'pa ... ol1': [1, 2], 'col2': [3, 4]}; \
pd.DataFrame(data=d)", Background -> LightYellow]}, Background -> {{GrayLevel[0.95], 
                GrayLevel[1]}}, Frame -> LightGray], "No local variables"}]}, True]}], 
      FontFamily -> "Courier"]}, True]]]
```

---

PIL images are automatically converted to ``Image`` :

```wl
In[1]:= ExternalEvaluate[{"Python", "Evaluator" -> <|"Dependencies" -> "Pillow"|>}, "from PIL import Image; Image.new('RGB', (60, 30), color = 'red')"]

Out[1]= [image]
```

---

Generators are automatically converted to ``List`` :

```wl
In[1]:= ExternalEvaluate["Python", "(i * 2 for i in [1, 2, 3])"]

Out[1]= {2, 4, 6}
```

Any Python object that is iterable will be automatically converted to a ``List`` unless an explicit conversion method is implemented:

```wl
In[2]:= ExternalEvaluate["Python", "range(10)"]

Out[2]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
```

---

Create a session to work with pyarrow module:

```wl
In[1]:= session = StartExternalSession[{"Python", "Evaluator" -> <|"Dependencies" -> {"pyarrow", "pandas"}|>, "SessionProlog" -> "import pyarrow, datetime, pandas"}];
```

Create a ``Tabular`` object from Python data:

```wl
In[2]:=
ExternalEvaluate[session, 
	"pyarrow.Table.from_pydict({'age': [21, 22, 23], 'name': ['jack', 'nelly', 'isabel'], 'last_seen': [datetime.datetime.now(), datetime.datetime.now(), datetime.datetime.now()]})"
	]

Out[2]=
Tabular[Association["RawSchema" -> Association["ColumnProperties" -> 
     Association["age" -> Association["ElementType" -> "Integer64"], 
      "name" -> Association["ElementType" -> "String"], "last_seen" -> 
       Association["ElementType" ->  ... ularColumn[Association["Data" -> {3, {{{1750088721675558, 1750088721675574, 
               1750088721675575}, {}, None}}, None}, "ElementType" -> TypeSpecifier["Date"][
            "Integer64", "Microsecond" -> "Instant", Automatic, None]]]}}]]]]
```

Use pyarrow to create ``Tabular`` from data of different shapes:

```wl
In[3]:=
ExternalEvaluate[session, 
	"pylist = [{'Runner': 'Jane', 'Position': 2, 'Time': datetime.timedelta(seconds = 3)}, {'Runner': 'Kim', 'Position': 1, 'Time': datetime.timedelta(seconds = 2.5)}]
pyarrow.Table.from_pylist(pylist)"
	]

Out[3]=
Tabular[Association["RawSchema" -> Association["ColumnProperties" -> 
     Association["Runner" -> Association["ElementType" -> "String"], 
      "Position" -> Association["ElementType" -> "Integer64"], 
      "Time" -> Association["ElementType" -> ...  {{2, 1}, {}, None}, 
          "ElementType" -> "Integer64"]], TabularColumn[Association[
          "Data" -> {2, {{{3000000, 2500000}, {}, None}}, None}, "ElementType" -> 
           TypeSpecifier["Quantity"]["Integer64", "Microseconds"]]]}}]]]]

In[4]:=
ExternalEvaluate[session, 
	"n_legs=pyarrow.array([2,4,5,100])
animals=pyarrow.array(['Flamingo','Horse','Brittle stars','Centipede'])
pyarrow.Table.from_arrays([animals, n_legs], names=['animal', 'legs'])"
	]

Out[4]=
Tabular[Association["RawSchema" -> Association["ColumnProperties" -> 
     Association["animal" -> Association["ElementType" -> "String"], 
      "legs" -> Association["ElementType" -> "Integer64"]], "KeyColumns" -> None, 
    "Backend" -> "Wolfram ... ata" -> {{0, {0, 8, 13, 26, 35}, 
             "FlamingoHorseBrittle starsCentipede"}, {}, None}, "ElementType" -> "String"]], 
        TabularColumn[Association["Data" -> {{2, 4, 5, 100}, {}, None}, 
          "ElementType" -> "Integer64"]]}}]]]]
```

Pandas dataframes can be converted to ``Tabular`` objects by converting them to pyarrow first:

```wl
In[5]:=
ExternalEvaluate[session, 
	"df = pandas.DataFrame({'year': [2020, 2022, 2019, 2021],
                   'n_legs': [2, 4, 5, 100],
                   'animals': ['Flamingo', 'Horse', 'Brittle stars', 'Centipede']})
pyarrow.Table.from_pandas(df)"
	]

Out[5]=
Tabular[Association["RawSchema" -> Association["ColumnProperties" -> 
     Association["year" -> Association["ElementType" -> "Integer64"], 
      "n_legs" -> Association["ElementType" -> "Integer64"], 
      "animals" -> Association["ElementType"  ...          "Data" -> {{2, 4, 5, 100}, {}, None}, "ElementType" -> "Integer64"]], 
        TabularColumn[Association["Data" -> {{0, {0, 8, 13, 26, 35}, 
             "FlamingoHorseBrittle starsCentipede"}, {}, None}, "ElementType" -> "String"]]}}]]]]
```

Close the session:

```wl
In[6]:= DeleteObject[session]
```

---

String templates can be used to insert Wolfram Language expressions into Python code. Set two variables:

```wl
In[1]:=
x = 2;
y = 4;
```

The expression ``x ^ 2 + y ^ 2`` is evaluated in the Wolfram Language, and the result is converted and inserted into the Python code string:

```wl
In[2]:= ExternalEvaluate["Python", "<* x^2 + y^2 *>"]

Out[2]= 20
```

#### Session Options (12)

##### "ReturnType" (3)

---

For the Python evaluation system, the default return type is ``"Expression"`` :

```wl
In[1]:= ExternalEvaluate["Python", "2+2"] === ExternalEvaluate["Python" -> "Expression", "2+2"]

Out[1]= True
```

---

Numbers, strings, lists and associations are automatically imported for the ``"Expression"`` return type:

```wl
In[1]:= ExternalEvaluate["Python", "[2, 3]"]

Out[1]= {2, 3}

In[2]:= MatchQ[%, {__Integer}]

Out[2]= True
```

---

The return type of ``"String"`` returns a string of the result by calling the Python function ``repr`` :

```wl
In[1]:= ExternalEvaluate["Python" -> "String", "[1, 2, u'א']"]

Out[1]= "[1, 2, 'א']"

In[2]:= ExternalEvaluate["Python", "repr([1, 2, u'א'])"]

Out[2]= "[1, 2, 'א']"
```

##### "Evaluator" (5)

---

Evaluate Python code using a specified ``"Evaluator"`` :

```wl
In[1]:= ExternalEvaluate[{"Python", "Evaluator" -> "/opt/homebrew/bin/python3"}, "import sys; sys.executable"]

Out[1]= "/opt/homebrew/opt/python@3.13/bin/python3.13"
```

---

An ``Association`` can be used to automatically provision a Python virtual environment:

```wl
In[1]:=
ExternalEvaluate[
	{
	"Python", 
	"Evaluator" -> <|"Dependencies" -> {"emoji"}|>
	}, 
	"import emoji; emoji.emojize('Emojis are :thumbs_up:')"
	]

Out[1]= "Emojis are 👍"
```

---

``"Dependencies"`` can be a list of strings that specify Python packages, using pip conventions to specify versions:

```wl
In[1]:=
ExternalEvaluate[
	{
	"Python", 
	"Evaluator" -> <|"Dependencies" -> {"emoji==2.8.0", "numpy>=1.26.1"}|>
	}, 
	"import emoji; emoji.emojize('This is a :bug:')"
	]

Out[1]= "This is a 🐛"
```

The ``File`` wrapper can also be used in order to specify ``"Dependencies"`` for an evaluator:

```wl
In[2]:= path = Export["requirements.txt", "emoji==2.8.0"];

In[3]:=
ExternalEvaluate[
	{
	"Python", 
	"Evaluator" -> <|"Dependencies" -> File[path]|>
	}, 
	"import emoji; emoji.emojize('This is an :alien:')"
	]

Out[3]= "This is an 👽"
```

---

Specify an ``"EnvironmentID"`` to customize the virtual environment folder name:

```wl
In[1]:=
ExternalEvaluate[
	{
	"Python", 
	"Evaluator"  -> <|
	"Dependencies" -> {"emoji"}, 
	"EnvironmentID" -> "myenv" 
	|>
	}, 
	"import sys; sys.executable"
	]

Out[1]= "/Users/rdv/Library/Wolfram/ApplicationData/ExternalEvaluate/Envs/Python/Cache/archive-v0/iSQP0k9LNKE0BeObaYbKK/bin/python3"
```

---

``"PythonRuntime"`` can be used to download a specific version:

```wl
In[1]:=
ExternalEvaluate[
	{
	"Python", 
	"Evaluator"  -> <|
	"Dependencies" -> {"emoji"}, 
	"EnvironmentID" -> "emoji-env-3.10", 
	"PythonRuntime" -> "3.10"
	|>
	}, 
	"import sys; sys.version"
	]

Out[1]= "3.10.17 (main, Apr  9 2025, 03:47:39) [Clang 20.1.0 ]"
```

Use the ``File`` wrapper to use your own Python installation:

```wl
In[2]:=
ExternalEvaluate[
	{
	"Python", 
	"Evaluator"  -> <|
	"Dependencies" -> {"emoji"}, 
	"EnvironmentID" -> "my-3.9-env", 
	"PythonRuntime" -> File["/opt/homebrew/bin/python3"]
	|>
	}, 
	"import sys; sys.version"
	]

Out[2]= "3.13.3 (main, Apr  8 2025, 13:54:08) [Clang 17.0.0 (clang-1700.0.13.3)]"
```

##### "SessionProlog" (1)

---

Use ``"SessionProlog"`` to perform a side effect at the start of a session:

```wl
In[1]:= ExternalEvaluate[{"Python", "SessionProlog" -> "print('session started')"}, "print('evaluating code'); 2+2"]

During evaluation of In[1]:= "session started"

During evaluation of In[1]:= "evaluating code"

Out[1]= 4
```

##### "SessionEpilog" (1)

---

Use ``"SessionEpilog"`` to perform a side effect at the end of a session:

```wl
In[1]:= ExternalEvaluate[{"Python", "SessionEpilog" -> "print('session ended')"}, "print('evaluating code'); 2+2"]

During evaluation of In[1]:= "evaluating code"

During evaluation of In[1]:= "session ended"

Out[1]= 4
```

##### "Prolog" (1)

---

Use ``"Prolog"`` to perform a side effect before every evaluation:

```wl
In[1]:= ExternalEvaluate[{"Python", "SessionProlog" -> "n=0", "Prolog" -> "print('n was', n)"}, {"n += 3", "n += 3"}]

During evaluation of In[1]:= "n was 0"

During evaluation of In[1]:= "n was 3"

Out[1]= {Null, Null}
```

##### "Epilog" (1)

---

Use ``"Epilog"`` to perform a side effect after every evaluation:

```wl
In[1]:= ExternalEvaluate[{"Python", "SessionProlog" -> "n=0", "Prolog" -> "print('n was', n)", "Epilog" -> "print('n is', n)"}, {"n += 3", "n += 3"}]

During evaluation of In[1]:= "n was 0"

During evaluation of In[1]:= "n is 3"

During evaluation of In[1]:= "n was 3"

During evaluation of In[1]:= "n is 6"

Out[1]= {Null, Null}
```

#### Command Options (11)

##### "Command" (4)

---

When only a string of Python code is provided, the command is directly executed:

```wl
In[1]:= ExternalEvaluate["Python", "range(3)"]

Out[1]= {0, 1, 2}
```

The above is equivalent to writing the command using this form:

```wl
In[2]:= ExternalEvaluate["Python", <|"Command" -> "range(3)"|>]

Out[2]= {0, 1, 2}
```

---

Use a ``File`` wrapper to run the code in a file:

```wl
In[1]:=
ExternalEvaluate["Python", {
	<|"Command" -> File["ExampleData/add.py"]|>, 
	<|"Command" -> "add2(3)"|>
	}]

Out[1]=
{ExternalFunction[ExternalSessionObject["dyniuhl-whaosp-1avig1svhffc7"], 
 ExternalOperation["GetReference", 4316980704], Association["Arguments" -> {"x"}, 
  "IsModule" -> False, "IsClass" -> False, "IsFunction" -> True, "IsMethod" -> False, 
  "IsCallable" -> True]], 5}
```

The above is equivalent to writing the command using this form:

```wl
In[2]:=
ExternalEvaluate["Python", {
	File["ExampleData/add.py"], 
	"add2(3)"
	}]

Out[2]=
{ExternalFunction[ExternalSessionObject["zeiaf-schnuetz-17fusvdwec5pz"], 
 ExternalOperation["GetReference", 4318979552], Association["Arguments" -> {"x"}, 
  "IsModule" -> False, "IsClass" -> False, "IsFunction" -> True, "IsMethod" -> False, 
  "IsCallable" -> True]], 5}
```

---

Use a ``URL`` wrapper to directly run code hosted online:

```wl
In[1]:=
ExternalEvaluate["Python", {
	<|"Command" -> URL["https://exampledata.wolfram.com/script.py"]|>, 
	<|"Command" -> "addtwo(2)"|>
	}]

Out[1]=
{ExternalFunction[ExternalSessionObject["kneauntz-wriaorn-0rrydkgw80t8n"], 
 ExternalOperation["GetReference", 4351927632], Association["Arguments" -> {"a"}, 
  "IsModule" -> False, "IsClass" -> False, "IsFunction" -> True, "IsMethod" -> False, 
  "IsCallable" -> True]], 4}
```

The above is equivalent to writing the command using this form:

```wl
In[2]:=
ExternalEvaluate["Python", {
	URL["https://exampledata.wolfram.com/script.py"], 
	"addtwo(3)"
	}]

Out[2]=
{ExternalFunction[ExternalSessionObject["knerds-mcgoidy-0mlwgzdt6oie0"], 
 ExternalOperation["GetReference", 4323616080], Association["Arguments" -> {"a"}, 
  "IsModule" -> False, "IsClass" -> False, "IsFunction" -> True, "IsMethod" -> False, 
  "IsCallable" -> True]], 5}
```

---

Put code in a ``CloudObject`` :

```wl
In[1]:= cloudObj = CloudExport["print('Hello World!')", "Text", CloudObject["hello-world-py"]]

Out[1]= CloudObject["https://www.wolframcloud.com/obj/riccardod/hello-world-py"]
```

Evaluate directly from the cloud:

```wl
In[2]:= ExternalEvaluate["Python", <|"Command" -> cloudObj|>]

During evaluation of In[2]:= "Hello World!"
```

The above is equivalent to writing the command using this form:

```wl
In[3]:= ExternalEvaluate["Python", cloudObj]

During evaluation of In[3]:= "Hello World!"
```

##### "ReturnType" (1)

---

By default, the command is executed using the ``"ReturnType"`` specified during the session creation:

```wl
In[1]:=
ExternalEvaluate[
	{"Python", "ReturnType" -> "String"}, 
	"{'a': 2}"
	]

Out[1]= "{'a': 2}"
```

Specifying a ``"ReturnType"`` in the command overrides the ``"ReturnType"`` for the session:

```wl
In[2]:=
ExternalEvaluate[
	{"Python", "ReturnType" -> "String"}, 
	{
	<|"Command" -> "{'a': 2}"|>, 
	<|"Command" -> "{'a': 2}", "ReturnType" -> "Expression"|>
	}
	]

Out[2]= {"{'a': 2}", <|"a" -> 2|>}
```

##### "Arguments" (2)

---

Use ``"Arguments"`` to call a Python function with arguments:

```wl
In[1]:=
ExternalEvaluate[
	"Python", 
	<|"Command" -> "range", "Arguments" -> {0, 5}|>
	]

Out[1]= {0, 1, 2, 3, 4}
```

When a non-list argument is provided, a single argument is passed to the function:

```wl
In[2]:=
ExternalEvaluate[
	"Python", 
	<|"Command" -> "repr", "Arguments" -> 1|>
	]

Out[2]= "1"
```

If you need to pass a list as the first argument, you must wrap it with an extra list explicitly:

```wl
In[3]:=
ExternalEvaluate[
	"Python", 
	{
	<|"Command" -> "repr", "Arguments" -> 1|>, 
	<|"Command" -> "repr", "Arguments" -> {1}|>, 
	<|"Command" -> "repr", "Arguments" -> {{1}}|>
	}
	]

Out[3]= {"1", "1", "(1,)"}
```

---

You can define a function inside ``"Command"`` and directly call it with ``"Arguments"`` :

```wl
In[1]:=
ExternalEvaluate[
	"Python", 
	<|"Command" -> "lambda a, b: a+b", "Arguments" -> {1, 3}|>
	]

Out[1]= 4
```

The same result can be achieved by using a ``Rule`` :

```wl
In[2]:=
ExternalEvaluate[
	"Python", 
	"lambda a, b: a+b" -> {1, 3}
	]

Out[2]= 4
```

You can also pass arguments by creating an ``ExternalFunction`` :

```wl
In[3]:= session = StartExternalSession["Python"]

Out[3]= ExternalSessionObject["hrearf-theatz-1o9917k6x2068"]

In[4]:= function = ExternalFunction[session, "lambda a, b: a + b"]

Out[4]= ExternalFunction[ExternalSessionObject["hrearf-theatz-1o9917k6x2068"], "lambda a, b: a + b"]

In[5]:= function[1, 3]

Out[5]= 4

In[6]:= DeleteObject[session]
```

##### "Constants" (1)

---

Use ``"Constants"`` to permanently set global variables before the command runs:

```wl
In[1]:=
ExternalEvaluate[
	"Python", 
	<|"Constants" -> <|"a" -> 2, "b" -> 3|>, "Command" -> "a + b + 3"|>
	]

Out[1]= 8
```

##### "TemplateArguments" (3)

---

When running a command, you can inline a ``TemplateExpression`` :

```wl
In[1]:=
x = RandomReal[]
ExternalEvaluate["Python", "1 + <* x *>"]

Out[1]= 0.632785

Out[1]= 1.63279
```

You can explicitly fill ``TemplateSlot`` using ``"TemplateArguments"`` :

```wl
In[2]:=
ExternalEvaluate[
	"Python", 
	<|"Command" -> "2 + ``", "TemplateArguments" -> 1|>
	]

Out[2]= 3
```

---

When a non-list argument is provided, a single template argument is passed to the template:

```wl
In[1]:=
ExternalEvaluate[
	"Python", 
	<|"Command" -> "repr(``)", "TemplateArguments" -> 1|>
	]

Out[1]= "1"
```

If you need to pass a list as the first argument, you must wrap it with an extra list explicitly:

```wl
In[2]:=
ExternalEvaluate[
	"Python", 
	{
	<|"Command" -> "repr(``)", "TemplateArguments" -> 1|>, 
	<|"Command" -> "repr(``)", "TemplateArguments" -> {1}|>, 
	<|"Command" -> "repr(``)", "TemplateArguments" -> {{1}}|>
	}
	]

Out[2]= {"1", "1", "(1,)"}
```

---

You can name template slots and use an ``Association`` to pass named arguments to the template:

```wl
In[1]:=
ExternalEvaluate[
	"Python", 
	<|"Command" -> "range(`start`, `end`, `step`)", "TemplateArguments" -> <|"start" -> 0, "end" -> 10, "step" -> 2|>|>
	]

Out[1]= {0, 2, 4, 6, 8}
```

#### External Operations (16)

##### "Eval" (1)

---

Run an ``ExternalOperation`` that represents arbitrary code evaluation in Python:

```wl
In[1]:= ExternalEvaluate["Python", ExternalOperation["Eval", "2+2"]]

Out[1]= 4
```

Use the second argument to pass an evaluation context:

```wl
In[2]:= ExternalEvaluate["Python", ExternalOperation["Eval", "a + b", <|"a" -> 2, "b" -> 3|>]]

Out[2]= 5
```

##### "Call" (3)

---

Define an ``ExternalOperation`` that creates a function in Python:

```wl
In[1]:= op = ExternalOperation["Eval", "max"]

Out[1]= ExternalOperation["Eval", "max"]
```

Define a function call by running the ``ExternalOperation`` ``"Call"`` :

```wl
In[2]:= call = ExternalOperation["Call", op, 1, 2]

Out[2]= ExternalOperation["Call", ExternalOperation["Eval", "max"], 1, 2]
```

Run the external operation representing the function call using ``ExternalEvaluate`` :

```wl
In[3]:= ExternalEvaluate["Python", call]

Out[3]= 2
```

Any argument of the ``"Call"`` operation can be an ``ExternalOperation`` :

```wl
In[4]:= ExternalEvaluate["Python", ExternalOperation["Call", op, 1, ExternalOperation["Eval", "2+2"]]]

Out[4]= 4
```

Arguments can also be passed directly in ``ExternalEvaluate`` by doing the following:

```wl
In[5]:= ExternalEvaluate["Python", op -> {1, 2}]

Out[5]= 2
```

The result is equivalent of running the following Python code:

```wl
In[6]:= ExternalEvaluate["Python", "max(1, 2)"]

Out[6]= 2
```

---

Create an ``ExternalFunction`` for a Python function:

```wl
In[1]:= max = ExternalFunction["Python", "max"]

Out[1]= ExternalFunction[Association["System" -> "Python"], "max"]
```

Call the function by running the operation ``"Call"`` :

```wl
In[2]:= ExternalEvaluate["Python", ExternalOperation["Call", max, 1, 2]]

Out[2]= 2
```

The same result can be achieved by doing the following:

```wl
In[3]:= ExternalEvaluate["Python", max -> {1, 2}]

Out[3]= 2
```

---

Create an ``ExternalObject`` for a Python function:

```wl
In[1]:= session = StartExternalSession["Python"]

Out[1]= ExternalSessionObject["heorr-goiad-0li50agubiovd"]

In[2]:= max = ExternalEvaluate[session, <|"Command" -> "max", "ReturnType" -> "ExternalObject"|>]

Out[2]=
ExternalObject[ExternalSessionObject["heorr-goiad-0li50agubiovd"], 
 ExternalOperation["GetReference", 4365771296], Association["IsModule" -> False, 
  "Module" -> "builtins", "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, 
  "IsCallable" -> True]]
```

Call the function by running the operation ``"Call"`` :

```wl
In[3]:= ExternalEvaluate[session, ExternalOperation["Call", max, 1, 2]]

Out[3]= 2
```

The same result can be achieved by doing the following:

```wl
In[4]:= ExternalEvaluate[session, max -> {1, 2}]

Out[4]= 2
```

Alternatively, you can use ``ExternalObject`` subvalues:

```wl
In[5]:= max[ExternalOperation["Call", 1, 2]]

Out[5]= 2
```

Close the session:

```wl
In[6]:= DeleteObject[session]
```

##### "GetAttribute" (1)

---

Start a Python session to work with dates:

```wl
In[1]:= session = StartExternalSession[{"Python", "SessionProlog" -> "import datetime"}];
```

Return an ``ExternalObject`` for a datetime object:

```wl
In[2]:= now = ExternalEvaluate[session, <|"Command" -> "datetime.datetime.now()", "ReturnType" -> "ExternalObject"|>]

Out[2]=
ExternalObject[ExternalSessionObject["spraatch-symbiish-05lnyfc3zkkhp"], 
 ExternalOperation["GetReference", 4351978256], Association["IsModule" -> False, 
  "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

Extract the year attribute by using ``"GetAttribute"`` :

```wl
In[3]:= ExternalEvaluate[session, ExternalOperation["GetAttribute", now, "year"]]

Out[3]= 2025
```

The same can be done using an ``ExternalObject`` subvalue:

```wl
In[4]:= now[ExternalOperation["GetAttribute", "year"]]

Out[4]= 2025
```

For the Python evaluator, ``"GetAttribute"`` is the default operation, and ``ExternalOperation`` can be omitted:

```wl
In[5]:= now["year"]

Out[5]= 2025
```

The result is equivalent to running the following Python code:

```wl
In[6]:= ExternalEvaluate[session, "datetime.datetime.now().year"]

Out[6]= 2025
```

Delete the session:

```wl
In[7]:= DeleteObject[session]
```

##### "SetAttribute" (1)

---

Start a Python session to work with decimal numbers:

```wl
In[1]:= session = StartExternalSession[{"Python", "SessionProlog" -> "from decimal import getcontext, Decimal"}];
```

Get the context for the decimal module:

```wl
In[2]:= context = ExternalEvaluate[session, "getcontext()"]

Out[2]=
ExternalObject[ExternalSessionObject["khugy-weupp-0wl2dg9v6ek4y"], 
 ExternalOperation["GetReference", 4346905488], Association["IsModule" -> False, 
  "Module" -> "decimal", "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, 
  "IsCallable" -> False]]
```

Set the precision to 6:

```wl
In[3]:= ExternalEvaluate[session, ExternalOperation["SetAttribute", context, "prec", 6]]
```

Check that the precision was set to 6:

```wl
In[4]:= ExternalEvaluate[session, ExternalOperation["GetAttribute", context, "prec"]]

Out[4]= 6

In[5]:= ExternalEvaluate[session, "Decimal('0') + Decimal('0.123456789')"]

Out[5]= 0.123457000000000000000000000
```

The result is equivalent to running the following Python code:

```wl
In[6]:= ExternalEvaluate[session, "getcontext().prec = 6"]
```

Delete the session:

```wl
In[7]:= DeleteObject[session]
```

##### "GetItem" (2)

---

Start a Python session:

```wl
In[1]:= session = StartExternalSession["Python"];
```

Create a Python dictionary and return it as an ``ExternalObject`` :

```wl
In[2]:= dict = ExternalEvaluate[session, <|"Command" -> "{'name': 'joe'}", "ReturnType" -> "ExternalObject"|>]

Out[2]=
ExternalObject[ExternalSessionObject["stouv-zish-09az3c03tok61"], 
 ExternalOperation["GetReference", 4323872384], Association["IsModule" -> False, 
  "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

Extract the ``"name"`` item by using ``"GetItem"`` :

```wl
In[3]:= ExternalEvaluate[session, ExternalOperation["GetItem", dict, "name"]]

Out[3]= "joe"
```

The result is equivalent to running the following Python code:

```wl
In[4]:= ExternalEvaluate[session, "{'name': 'joe'}['name']"]

Out[4]= "joe"
```

Delete the session:

```wl
In[5]:= DeleteObject[session]
```

---

Create an ``ExternalOperation`` that represents a dictionary:

```wl
In[1]:= dict = ExternalOperation["Eval", "{'name': 'joe'}"]

Out[1]= ExternalOperation["Eval", "{'name': 'joe'}"]
```

Create a new ``ExternalOperation`` to get the item ``"name"`` :

```wl
In[2]:= op = ExternalOperation["GetItem", dict, "name"]

Out[2]= ExternalOperation["GetItem", ExternalOperation["Eval", "{'name': 'joe'}"], "name"]
```

Run the operation using ``ExternalEvaluate`` :

```wl
In[3]:= ExternalEvaluate["Python", op]

Out[3]= "joe"
```

##### "SetItem" (1)

---

Start a Python session:

```wl
In[1]:= session = StartExternalSession["Python"];
```

Create an ``ExternalObject`` with a dictionary:

```wl
In[2]:= dict = ExternalEvaluate[session, <|"Command" -> "{}", "ReturnType" -> "ExternalObject"|>]

Out[2]=
ExternalObject[ExternalSessionObject["wriich-mcliesh-0e5f71xc9w69q"], 
 ExternalOperation["GetReference", 4319431936], Association["IsModule" -> False, 
  "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

Set the item ``"name"`` to ``"joe"`` :

```wl
In[3]:= dict[ExternalOperation["SetItem", "name", "joe"]]
```

Check that the item was set to ``"joe"`` :

```wl
In[4]:= dict[ExternalOperation["GetItem", "name"]]

Out[4]= "joe"
```

Get the whole dictionary as an association, by using ``Expression`` :

```wl
In[5]:= dict[Expression]

Out[5]= <|"name" -> "joe"|>
```

Delete the session:

```wl
In[6]:= DeleteObject[session]
```

##### "Import" (6)

---

Define an ``ExternalObject`` that imports the ``"datetime"`` module:

```wl
In[1]:= op = ExternalOperation["Import", "datetime"]

Out[1]= ExternalOperation["Import", "datetime"]
```

Return the module as an ``ExternalObject`` :

```wl
In[2]:= ExternalEvaluate["Python", op]

Out[2]=
ExternalObject[ExternalSessionObject["whuieds-brof-0r2wf2gu8ytiu"], 
 ExternalOperation["GetReference", 4348730800], Association["IsModule" -> True, "IsClass" -> False, 
  "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

---

Define an ``ExternalObject`` that imports the date from the ``"datetime"`` module:

```wl
In[1]:= op = ExternalOperation["Import", "datetime", "date"]

Out[1]= ExternalOperation["Import", "datetime", "date"]
```

Call the operation with arguments using ``ExternalEvaluate`` :

```wl
In[2]:= ExternalEvaluate["Python", op -> {2012, 10, 10}]

Out[2]= DateObject[{2012, 10, 10}, "Day"]
```

---

Define an ``ExternalObject`` that imports the ``"datetime"`` module:

```wl
In[1]:= session = StartExternalSession["Python"];

In[2]:= datetime = ExternalEvaluate[session, ExternalOperation["Import", "datetime"]]

Out[2]=
ExternalObject[ExternalSessionObject["baeny-hruieks-01rg7ahw2tdfl"], 
 ExternalOperation["GetReference", 4374995008], Association["IsModule" -> True, "IsClass" -> False, 
  "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

Use an ``ExternalFunction`` to call the ``"date"`` method:

```wl
In[3]:= ExternalFunction[datetime, "date"][2012, 10, 1]

Out[3]= DateObject[{2012, 10, 1}, "Day"]
```

Delete the session:

```wl
In[4]:= DeleteObject[session]
```

---

Define an ``ExternalObject`` that imports the fractions module:

```wl
In[1]:= session = StartExternalSession["Python"];

In[2]:= fractions = ExternalEvaluate[session, ExternalOperation["Import", "fractions"]]

Out[2]=
ExternalObject[ExternalSessionObject["mcgigy-traork-0ific6sfrdf0u"], 
 ExternalOperation["GetReference", 4340310560], Association["IsModule" -> True, "IsClass" -> False, 
  "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

Initialize the fraction by using ``ExternalObject`` subvalues:

```wl
In[3]:= fractions["Fraction", ExternalOperation["Call", 1, 2]]

Out[3]= (1/2)
```

The same can be done with the following syntax:

```wl
In[4]:= fractions["Fraction" -> {1, 2}]

Out[4]= (1/2)
```

Delete the session:

```wl
In[5]:= DeleteObject[session]
```

---

Define an ``"Import"`` operation that imports ``"ip_address"`` :

```wl
In[1]:= class = ExternalOperation["Import", "ipaddress", "ip_address"]

Out[1]= ExternalOperation["Import", "ipaddress", "ip_address"]
```

Create an address instance using ``ExternalEvaluate`` :

```wl
In[2]:= ExternalEvaluate["Python", class -> "192.168.1.220"]

Out[2]=
ExternalObject[ExternalSessionObject["mcfaiank-reish-1bus07tl8b5jw"], 
 ExternalOperation["GetReference", 4329703792], Association["IsModule" -> False, 
  "Module" -> "ipaddress", "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, 
  "IsCallable" -> False]]
```

Use ``String`` as the return type to show the Python string version of the instance:

```wl
In[3]:= ExternalEvaluate["Python", <|"Command" -> class, "Arguments" -> "192.168.1.220", "ReturnType" -> "String"|>]

Out[3]= "IPv4Address('192.168.1.220')"
```

---

Define an ``"Import"`` operation that imports ``"ip_address"`` :

```wl
In[1]:= class = ExternalOperation["Import", "ipaddress", "ip_address"]

Out[1]= ExternalOperation["Import", "ipaddress", "ip_address"]
```

Create an address instance using another ``ExternalOperation`` :

```wl
In[2]:= instance = ExternalOperation["Call", class, "192.168.1.220"]

Out[2]= ExternalOperation["Call", ExternalOperation["Import", "ipaddress", "ip_address"], "192.168.1.220"]
```

Execute the operation in ``ExternalEvaluate`` :

```wl
In[3]:= ExternalEvaluate["Python", <|"Command" -> instance, "ReturnType" -> "String"|>]

Out[3]= "IPv4Address('192.168.1.220')"
```

##### "Cast" (1)

---

Create an ``ExternalObject`` that represents the current date:

```wl
In[1]:= session = StartExternalSession["Python"];

In[2]:= now = ExternalEvaluate[session, <|"Command" -> "import datetime; datetime.datetime.now()", "ReturnType" -> "ExternalObject"|>]

Out[2]=
ExternalObject[ExternalSessionObject["hyieurd-dreuns-13yd2n2i0kup3"], 
 ExternalOperation["GetReference", 4327474640], Association["IsModule" -> False, 
  "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

Use ``"Expression"`` to return the object as a Wolfram Language expression:

```wl
In[3]:= ExternalEvaluate[session, ExternalOperation["Cast", now, "Expression"]]

Out[3]= DateObject[{2025, 6, 16, 15, 45, 38.6044}, "Instant", "Gregorian", None]
```

The ``Cast`` operation can also run in ``ExternalObject`` subvalues:

```wl
In[4]:= now[ExternalOperation["Cast", "Expression"]]

Out[4]= DateObject[{2025, 6, 16, 15, 45, 38.6044}, "Instant", "Gregorian", None]
```

The symbol ``Expression`` is a shortcut for the same:

```wl
In[5]:= now[Expression]

Out[5]= DateObject[{2025, 6, 16, 15, 45, 38.6044}, "Instant", "Gregorian", None]
```

Return the object as a string:

```wl
In[6]:= now[ExternalOperation["Cast", "String"]]

Out[6]= "datetime.datetime(2025, 6, 16, 15, 45, 38, 604355)"
```

The symbol ``String`` is a shortcut for the same:

```wl
In[7]:= now[String]

Out[7]= "datetime.datetime(2025, 6, 16, 15, 45, 38, 604355)"
```

Return the object as an ``ExternalObject`` :

```wl
In[8]:= now[ExternalOperation["Cast", "ExternalObject"]]

Out[8]=
ExternalObject[ExternalSessionObject["hyieurd-dreuns-13yd2n2i0kup3"], 
 ExternalOperation["GetReference", 4327474640], Association["IsModule" -> False, 
  "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

The symbol ``ExternalObject`` is a shortcut for the same:

```wl
In[9]:= now[ExternalObject]

Out[9]=
ExternalObject[ExternalSessionObject["hyieurd-dreuns-13yd2n2i0kup3"], 
 ExternalOperation["GetReference", 4327474640], Association["IsModule" -> False, 
  "IsClass" -> False, "IsFunction" -> False, "IsMethod" -> False, "IsCallable" -> False]]
```

The same can be achieved by using ``"ReturnType"`` in ``ExternalEvaluate`` :

```wl
In[10]:= ExternalEvaluate[session, <|"Command" -> now, "ReturnType" -> "String"|>]

Out[10]= "datetime.datetime(2025, 6, 16, 15, 45, 38, 604355)"
```

Delete the session:

```wl
In[11]:= DeleteObject[session]
```

### Applications (3)

Expose the Python range function in Wolfram Language:

```wl
In[1]:=
range[args___] := 
	ExternalEvaluate["Python", "range" -> {args}]
```

Use the function:

```wl
In[2]:= range[10]

Out[2]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
```

---

Create a function that returns AST for a string of Python code using an AST module:

```wl
In[1]:=
getPythonAST[code_] := 
	Last @ ExternalEvaluate[{"Python", "Evaluator" -> <|"Dependencies" -> {"ast2json"}|>}, {
	"import ast, ast2json", 
	"lambda code: ast2json.ast2json(ast.parse(code, mode='eval'))" -> code
	}]
```

Use the function:

```wl
In[2]:= getPythonAST["lambda a: [i + 2 for i in a]"]

Out[2]= <|"_type" -> "Expression", "body" -> <|"_type" -> "Lambda", "args" -> <|"_type" -> "arguments", "args" -> {<|"_type" -> "arg", "annotation" -> Null, "arg" -> "a", "col_offset" -> 7, "end_col_offset" -> 8, "end_lineno" -> 1, "lineno" -> 1, "type_com ...  <|"_type" -> "Name", "col_offset" -> 21, "ctx" -> <|"_type" -> "Store"|>, "end_col_offset" -> 22, "end_lineno" -> 1, "id" -> "i", "lineno" -> 1|>|>}, "lineno" -> 1|>, "col_offset" -> 0, "end_col_offset" -> 28, "end_lineno" -> 1, "lineno" -> 1|>|>
```

---

Use Pygments to create a function that does syntax highlighting of a block of code:

```wl
In[1]:=
formatCode[lang_, code_]  := 
	Replace[
	ExternalEvaluate[{"Python", "Evaluator" -> <|"Dependencies" -> {"pygments"}|>}, {
	"from pygments.lexers import get_lexer_by_name", 
	"from pygments import highlight", 
	"from pygments.formatter import Formatter", 
	"from wolframclient.serializers import export", 
	"F = type('WLFormatter', (Formatter, ), dict(
	format = lambda self, tokensource, outfile: outfile.write(export(tokensource).decode('utf-8'))
))", 
	"lambda lang, code: highlight(code, get_lexer_by_name(lang), F())" -> {lang, code}
	}
	], 
	{___, b_String} :> formatTokens[ImportString[b, "WL"]]
	]
getColorForType[expr_] := getColorForType[expr] = RandomColor[]
formatTokens[tokens_] := Row @ Apply[
	Style[#2, getColorForType[#1]]&, 
	tokens, 
	{1}
	]
```

Use the function:

```wl
In[2]:= formatCode["python", "map(lambda a: a+2, [r for i in range(10)])"]

Out[2]=
"map""(""lambda"" ""a"":"" ""a""+""2"","" ""[""r"" ""for"" ""i"" ""in"" ""range""(""10"")""]"")""
"

In[3]:= formatCode["sql", "select a as b from users where b = 2 limit 10"]

Out[3]=
"select"" ""a"" ""as"" ""b"" ""from"" ""users"" ""where"" ""b"" ""="" ""2"" ""limit"" ""10""
"

In[4]:= formatCode["javascript", "(a, b) => [a, b].map(x => x + 2)"]

Out[4]=
"(""a"","" ""b"")"" ""=>"" ""[""a"","" ""b""]"".""map""(""x"" ""=>"" ""x"" ""+"" ""2"")""
"
```

### Properties & Relations (1)

You can use WolframClientForPython to return expressions from Python:

```wl
In[1]:=
session = StartExternalSession["Python"];
ExternalEvaluate[session, "from wolframclient.language import wl"]

In[2]:= ExternalEvaluate[session, "wl.Quantity(3, 'Meters')"]

Out[2]= Quantity[3, "Meters"]
```

Expressions automatically evaluate after they are transferred in a kernel.

```wl
In[3]:= ExternalEvaluate[session, "wl.Range(10)"]

Out[3]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
```

Use ``Hold`` to control evaluation:

```wl
In[4]:= expr = ExternalEvaluate[session, "wl.Hold(wl.Range(10))"]

Out[4]= Hold[Range[10]]

In[5]:= ReleaseHold[expr]

Out[5]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
```

Close the session:

```wl
In[6]:= DeleteObject[session]
```

### Possible Issues (1)

Generators are automatically converted to ``List`` :

```wl
In[1]:= ExternalEvaluate["Python", "(i ** 2 for i in range(5))"]

Out[1]= {0, 1, 4, 9, 16}
```

Returning an infinite generator will block your kernel forever:

```wl
In[2]:=
TimeConstrained[
	ExternalEvaluate["Python", "from itertools import repeat; iter(i for i in repeat(1))"], 
	5
	]

Out[2]= $Aborted
```

## See Also

* [`ExternalEvaluate`](https://reference.wolfram.com/language/ref/ExternalEvaluate.en.md)
* [`ExternalObject`](https://reference.wolfram.com/language/ref/ExternalObject.en.md)
* [`ExternalOperation`](https://reference.wolfram.com/language/ref/ExternalOperation.en.md)
* [`ExternalFunction`](https://reference.wolfram.com/language/ref/ExternalFunction.en.md)
* [`StartExternalSession`](https://reference.wolfram.com/language/ref/StartExternalSession.en.md)
* [`PythonExpression`](https://reference.wolfram.com/language/ref/format/PythonExpression.en.md)
* [`Shell`](https://reference.wolfram.com/language/ref/externalevaluationsystem/Shell.en.md)
* [`SQL`](https://reference.wolfram.com/language/ref/externalevaluationsystem/SQL.en.md)

## Related Guides

* [External Interpreted Language Interfaces](https://reference.wolfram.com/language/guide/ExternalInterpretedLanguageInterfaces.en.md)
* [External Language Interfaces](https://reference.wolfram.com/language/guide/ExternalLanguageInterfaces.en.md)
* [Wolfram Client Library for Python](https://reference.wolfram.com/language/guide/WolframClientLibraryForPython.en.md)

## Related Workflows

* [Configure Python for ExternalEvaluate](https://reference.wolfram.com/language/workflow/ConfigurePythonForExternalEvaluate.en.md)

## History

* [Introduced in 2018 (11.3)](https://reference.wolfram.com/language/guide/SummaryOfNewFeaturesIn113.en.md) \| [Updated in 2024 (14.1)](https://reference.wolfram.com/language/guide/SummaryOfNewFeaturesIn141.en.md)