Struct pyo3::marker::Python

source ·
pub struct Python<'py>(_);
Expand description

A marker token that represents holding the GIL.

It serves three main purposes:

  • It provides a global API for the Python interpreter, such as Python::eval.
  • It can be passed to functions that require a proof of holding the GIL, such as Py::clone_ref.
  • Its lifetime represents the scope of holding the GIL which can be used to create Rust references that are bound to it, such as &PyAny.

Note that there are some caveats to using it that you might need to be aware of. See the Deadlocks and Releasing and freeing memory paragraphs for more information about that.

Obtaining a Python token

The following are the recommended ways to obtain a Python token, in order of preference:

  • In a function or method annotated with #[pyfunction] or #[pymethods] you can declare it as a parameter, and PyO3 will pass in the token when Python code calls it.
  • If you already have something with a lifetime bound to the GIL, such as &PyAny, you can use its .py() method to get a token.
  • When you need to acquire the GIL yourself, such as when calling Python code from Rust, you should call Python::with_gil to do that and pass your code as a closure to it.

Deadlocks

Note that the GIL can be temporarily released by the Python interpreter during a function call (e.g. importing a module). In general, you don’t need to worry about this because the GIL is reacquired before returning to the Rust code:

`Python` exists   |=====================================|
GIL actually held |==========|         |================|
Rust code running |=======|                |==|  |======|

This behaviour can cause deadlocks when trying to lock a Rust mutex while holding the GIL:

  • Thread 1 acquires the GIL
  • Thread 1 locks a mutex
  • Thread 1 makes a call into the Python interpreter which releases the GIL
  • Thread 2 acquires the GIL
  • Thread 2 tries to locks the mutex, blocks
  • Thread 1’s Python interpreter call blocks trying to reacquire the GIL held by thread 2

To avoid deadlocking, you should release the GIL before trying to lock a mutex or awaiting in asynchronous code, e.g. with Python::allow_threads.

Releasing and freeing memory

The Python type can be used to create references to variables owned by the Python interpreter, using functions such as Python::eval and PyModule::import. These references are tied to a GILPool whose references are not cleared until it is dropped. This can cause apparent “memory leaks” if it is kept around for a long time.

use pyo3::prelude::*;
use pyo3::types::PyString;

Python::with_gil(|py| -> PyResult<()> {
    for _ in 0..10 {
        let hello: &PyString = py.eval("\"Hello World!\"", None, None)?.extract()?;
        println!("Python says: {}", hello.to_str()?);
        // Normally variables in a loop scope are dropped here, but `hello` is a reference to
        // something owned by the Python interpreter. Dropping this reference does nothing.
    }
    Ok(())
})
// This is where the `hello`'s reference counts start getting decremented.

The variable hello is dropped at the end of each loop iteration, but the lifetime of the pointed-to memory is bound to Python::with_gil’s GILPool which will not be dropped until the end of Python::with_gil’s scope. Only then is each hello’s Python reference count decreased. This means that at the last line of the example there are 10 copies of hello in Python’s memory, not just one at a time as we might expect from Rust’s scoping rules.

See the Memory Management chapter of the guide for more information about how PyO3 uses GILPool to manage memory.

Implementations§

Acquires the global interpreter lock, allowing access to the Python interpreter. The provided closure F will be executed with the acquired Python marker token.

If the auto-initialize feature is enabled and the Python runtime is not already initialized, this function will initialize it. See prepare_freethreaded_python for details.

If the current thread does not yet have a Python “thread state” associated with it, a new one will be automatically created before F is executed and destroyed after F completes.

Panics
  • If the auto-initialize feature is not enabled and the Python interpreter is not initialized.
Examples
use pyo3::prelude::*;

Python::with_gil(|py| -> PyResult<()> {
    let x: i32 = py.eval("5", None, None)?.extract()?;
    assert_eq!(x, 5);
    Ok(())
})

Like Python::with_gil except Python interpreter state checking is skipped.

Normally when the GIL is acquired, we check that the Python interpreter is an appropriate state (e.g. it is fully initialized). This function skips those checks.

Safety

If Python::with_gil would succeed, it is safe to call this function.

In most cases, you should use Python::with_gil.

A justified scenario for calling this function is during multi-phase interpreter initialization when Python::with_gil would fail before _Py_InitializeMain is called because the interpreter is only partially initialized.

Behavior in other scenarios is not documented.

👎Deprecated since 0.17.0: prefer Python::with_gil

Acquires the global interpreter lock, allowing access to the Python interpreter.

If the auto-initialize feature is enabled and the Python runtime is not already initialized, this function will initialize it. See prepare_freethreaded_python for details.

Most users should not need to use this API directly, and should prefer one of two options:

  1. If implementing #[pymethods] or #[pyfunction], declare py: Python as an argument. PyO3 will pass in the token to grant access to the GIL context in which the function is running.
  2. Use Python::with_gil to run a closure with the GIL, acquiring only if needed.
Panics
  • If the auto-initialize feature is not enabled and the Python interpreter is not initialized.
  • If multiple GILGuards are not dropped in in the reverse order of acquisition, PyO3 may panic. It is recommended to use Python::with_gil instead to avoid this.
Notes

The return type from this function, GILGuard, is implemented as a RAII guard around PyGILState_Ensure. This means that multiple acquire_gil() calls are allowed, and will not deadlock. However, GILGuards must be dropped in the reverse order to acquisition. If PyO3 detects this order is not maintained, it will panic when the out-of-order drop occurs.

Deprecation

This API has been deprecated for several reasons:

  • GIL drop order tracking has turned out to be error prone. With a scoped API like Python::with_gil, these are always dropped in the correct order.
  • It promotes passing and keeping the GILGuard around, which is almost always not what you actually want.

Temporarily releases the GIL, thus allowing other Python threads to run. The GIL will be reacquired when F’s scope ends.

If you don’t need to touch the Python interpreter for some time and have other Python threads around, this will let you run Rust-only code while letting those other Python threads make progress.

Only types that implement Ungil can cross the closure. See the module level documentation for more information.

If you need to pass Python objects into the closure you can use Py<T>to create a reference independent of the GIL lifetime. However, you cannot do much with those without a Python token, for which you’d need to reacquire the GIL.

Example: Releasing the GIL while running a computation in Rust-only code
use pyo3::prelude::*;

#[pyfunction]
fn sum_numbers(py: Python<'_>, numbers: Vec<u32>) -> PyResult<u32> {
    // We release the GIL here so any other Python threads get a chance to run.
    py.allow_threads(move || {
        // An example of an "expensive" Rust calculation
        let sum = numbers.iter().sum();

        Ok(sum)
    })
}

Please see the Parallelism chapter of the guide for a thorough discussion of using Python::allow_threads in this manner.

Example: Passing borrowed Python references into the closure is not allowed
use pyo3::prelude::*;
use pyo3::types::PyString;

fn parallel_print(py: Python<'_>) {
    let s = PyString::new(py, "This object cannot be accessed without holding the GIL >_<");
    py.allow_threads(move || {
        println!("{:?}", s); // This causes a compile error.
    });
}

Evaluates a Python expression in the given context and returns the result.

If globals is None, it defaults to Python module __main__. If locals is None, it defaults to the value of globals.

Examples
let result = py.eval("[i * 10 for i in range(5)]", None, None).unwrap();
let res: Vec<i64> = result.extract().unwrap();
assert_eq!(res, vec![0, 10, 20, 30, 40])

Executes one or more Python statements in the given context.

If globals is None, it defaults to Python module __main__. If locals is None, it defaults to the value of globals.

Examples
use pyo3::{
    prelude::*,
    types::{PyBytes, PyDict},
};
Python::with_gil(|py| {
    let locals = PyDict::new(py);
    py.run(
        r#"
import base64
s = 'Hello Rust!'
ret = base64.b64encode(s.encode('utf-8'))
"#,
        None,
        Some(locals),
    )
    .unwrap();
    let ret = locals.get_item("ret").unwrap();
    let b64: &PyBytes = ret.downcast().unwrap();
    assert_eq!(b64.as_bytes(), b"SGVsbG8gUnVzdCE=");
});

You can use py_run! for a handy alternative of run if you don’t need globals and unwrapping is OK.

Gets the Python type object for type T.

Imports the Python module with the specified name.

Gets the Python builtin value None.

Gets the Python builtin value NotImplemented.

Gets the running Python interpreter version as a string.

Examples
Python::with_gil(|py| {
    // The full string could be, for example:
    // "3.10.0 (tags/v3.10.0:b494f59, Oct  4 2021, 19:00:18) [MSC v.1929 64 bit (AMD64)]"
    assert!(py.version().starts_with("3."));
});

Gets the running Python interpreter version as a struct similar to sys.version_info.

Examples
Python::with_gil(|py| {
    // PyO3 supports Python 3.7 and up.
    assert!(py.version_info() >= (3, 7));
    assert!(py.version_info() >= (3, 7, 0));
});

Registers the object in the release pool, and tries to downcast to specific type.

Registers the object in the release pool, and does an unchecked downcast to the specific type.

Safety

Callers must ensure that ensure that the cast is valid.

Registers the object pointer in the release pool, and does an unchecked downcast to the specific type.

Safety

Callers must ensure that ensure that the cast is valid.

Registers the owned object pointer in the release pool.

Returns Err(PyErr) if the pointer is NULL. Does an unchecked downcast to the specific type.

Safety

Callers must ensure that ensure that the cast is valid.

Registers the owned object pointer in release pool.

Returns None if the pointer is NULL. Does an unchecked downcast to the specific type.

Safety

Callers must ensure that ensure that the cast is valid.

Does an unchecked downcast to the specific type.

Panics if the pointer is NULL.

Safety

Callers must ensure that ensure that the cast is valid.

Does an unchecked downcast to the specific type.

Returns Err(PyErr) if the pointer is NULL.

Safety

Callers must ensure that ensure that the cast is valid.

Does an unchecked downcast to the specific type.

Returns None if the pointer is NULL.

Safety

Callers must ensure that ensure that the cast is valid.

Lets the Python interpreter check and handle any pending signals. This will invoke the corresponding signal handlers registered in Python (if any).

Returns Err(PyErr) if any signal handler raises an exception.

These signals include SIGINT (normally raised by CTRL + C), which by default raises KeyboardInterrupt. For this reason it is good practice to call this function regularly as part of long-running Rust functions so that users can cancel it.

Example
use pyo3::prelude::*;

#[pyfunction]
fn loop_forever(py: Python<'_>) -> PyResult<()> {
    loop {
        // As this loop is infinite it should check for signals every once in a while.
        // Using `?` causes any `PyErr` (potentially containing `KeyboardInterrupt`)
        // to break out of the loop.
        py.check_signals()?;

        // do work here
    }
}
Note

This function calls PyErr_CheckSignals() which in turn may call signal handlers. As Python’s signal API allows users to define custom signal handlers, calling this function allows arbitrary Python code inside signal handlers to run.

Create a new pool for managing PyO3’s owned references.

When this GILPool is dropped, all PyO3 owned references created after this GILPool will all have their Python reference counts decremented, potentially allowing Python to drop the corresponding Python objects.

Typical usage of PyO3 will not need this API, as Python::with_gil and Python::acquire_gil automatically create a GILPool where appropriate.

Advanced uses of PyO3 which perform long-running tasks which never free the GIL may need to use this API to clear memory, as PyO3 usually does not clear memory until the GIL is released.

Examples
Python::with_gil(|py| {
    // Some long-running process like a webserver, which never releases the GIL.
    loop {
        // Create a new pool, so that PyO3 can clear memory at the end of the loop.
        let pool = unsafe { py.new_pool() };

        // It is recommended to *always* immediately set py to the pool's Python, to help
        // avoid creating references with invalid lifetimes.
        let py = pool.python();

        // do stuff...
    }
});
Safety

Extreme care must be taken when using this API, as misuse can lead to accessing invalid memory. In addition, the caller is responsible for guaranteeing that the GIL remains held for the entire lifetime of the returned GILPool.

Two best practices are required when using this API:

  • From the moment new_pool() is called, only the Python token from the returned GILPool (accessible using .python()) should be used in PyO3 APIs. All other older Python tokens with longer lifetimes are unsafe to use until the GILPool is dropped, because they can be used to create PyO3 owned references which have lifetimes which outlive the GILPool.
  • Similarly, methods on existing owned references will implicitly refer back to the Python token which that reference was originally created with. If the returned values from these methods are owned references they will inherit the same lifetime. As a result, Rust’s lifetime rules may allow them to outlive the GILPool, even though this is not safe for reasons discussed above. Care must be taken to never access these return values after the GILPool is dropped, unless they are converted to Py<T> before the pool is dropped.

Unsafely creates a Python token with an unbounded lifetime.

Many of PyO3 APIs use Python<'_> as proof that the GIL is held, but this function can be used to call them unsafely.

Safety
  • This token and any borrowed Python references derived from it can only be safely used whilst the currently executing thread is actually holding the GIL.
  • This function creates a token with an unbounded lifetime. Safe code can assume that holding a Python<'py> token means the GIL is and stays acquired for the lifetime 'py. If you let it or borrowed Python references escape to safe code you are responsible for bounding the lifetime 'unbound appropriately. For more on unbounded lifetimes, see the nomicon.

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.