79632573

Date: 2025-05-21 18:36:57
Score: 1
Natty:
Report link

From a quick read what I gathered is there are essentially two ways you can accept a python dictionary:

  1. Accept a &Bound<'py, PyDict> where pyo3 automatically holds the GIL as long as your function runs.
  2. Accept a GIL independent Py<PyDict>, whenever you want to access it you have to get a hold of the GIL first with Python::with_gil or similar.

and two ways to work with it:

  1. Use the python dictionaries methods directly (PyDictMethods)
  2. Convert the PyDict to a HashMap (or other T: FromPyObject)

You can mix and match them as required, for example accepting a Bound and working directly with the methods:

use pyo3::{prelude::*, types::PyDict};

#[pyfunction]
pub fn process_dict(map: &Bound<'_, PyDict>) -> PyResult<()> {
    if let Some(value) = map.get_item("apple")? {
        println!("Value for 'apple': {}", value);
    } else {
        println!("Key not found");
    }

    Ok(())
}

Which has the advantage of you not having to care about the GIL and also no overhead necessary to convert the Python dict to a Rust type. The disadvantages are that the GIL is held for the entire runtime of the function and you're limited to what the python interface has to offer.

Or accepting a GIL independent Py and converting the value to a Rust type:

use std::collections::HashMap;

use pyo3::{prelude::*, types::PyDict};

#[pyfunction]
pub fn process_dict(map: Py<PyDict>) -> PyResult<()> {
    Python::with_gil(|gil| {
        let map: HashMap<String, i64> = map.extract(gil).unwrap();

        if let Some(value) = map.get("apple") {
            println!("Value for my 'apple': {}", value);
        } else {
            println!("Key not found");
        }
    });

    Ok(())
}

Advantages include having precise control where the GIL is held and getting to work with Rust native types while the disadvantages are the added complexity of handling the GIL as well as an overhead incurred for converting the PyDict to a HashMap

So to answer your questions directly:

How to solve this error? What is expected here and why?

Pass in a Python object that prooves you have the GIL because it's needed to safely access the dictionary.

Do I have to use the extract method here, is there a simpler method?

No, not at all necessary, you can directly work with a &Bound<'_, PyDict> and it's methods instead.

Is the map.extract() function expensive?

Somewhat, it has to copy and convert the python dictionary to a Rust type.

Reasons:
  • Blacklisted phrase (1): How to solve this error
  • Blacklisted phrase (0.5): why?
  • Blacklisted phrase (1): How to solve
  • RegEx Blacklisted phrase (1.5): How to solve this error?
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • High reputation (-2):
Posted by: cafce25