Struct numpy::PyArrayLike

source ·
pub struct PyArrayLike<'py, T, D, C = TypeMustMatch>(/* private fields */)
where
    T: Element,
    D: Dimension,
    C: Coerce;
Expand description

Receiver for arrays or array-like types.

When building API using NumPy in Python, it is common for functions to additionally accept any array-like type such as list[float] as arguments. PyArrayLike enables the same pattern in Rust extensions, i.e. by taking this type as the argument of a #[pyfunction], one will always get access to a PyReadonlyArray that will either reference to the NumPy array originally passed into the function or a temporary one created by converting the input type into a NumPy array.

Depending on whether TypeMustMatch or AllowTypeChange is used for the C type parameter, the element type must either match the specific type T exactly or will be cast to it by NumPy’s asarray.

§Example

PyArrayLike1<'py, T, TypeMustMatch> will enable you to receive both NumPy arrays and sequences

use pyo3::py_run;
use numpy::{get_array_module, PyArrayLike1, TypeMustMatch};

#[pyfunction]
fn sum_up<'py>(py: Python<'py>, array: PyArrayLike1<'py, f64, TypeMustMatch>) -> f64 {
    array.as_array().sum()
}

Python::with_gil(|py| {
    let np = get_array_module(py).unwrap();
    let sum_up = wrap_pyfunction!(sum_up)(py).unwrap();

    py_run!(py, np sum_up, r"assert sum_up(np.array([1., 2., 3.])) == 6.");
    py_run!(py, np sum_up, r"assert sum_up((1., 2., 3.)) == 6.");
});

but it will not cast the element type if that is required

use pyo3::prelude::*;
use pyo3::py_run;
use numpy::{get_array_module, PyArrayLike1, TypeMustMatch};

#[pyfunction]
fn sum_up<'py>(py: Python<'py>, array: PyArrayLike1<'py, i32, TypeMustMatch>) -> i32 {
    array.as_array().sum()
}

Python::with_gil(|py| {
    let np = get_array_module(py).unwrap();
    let sum_up = wrap_pyfunction!(sum_up)(py).unwrap();

    py_run!(py, np sum_up, r"assert sum_up((1., 2., 3.)) == 6");
});

whereas PyArrayLike1<'py, T, AllowTypeChange> will do even at the cost loosing precision

use pyo3::prelude::*;
use pyo3::py_run;
use numpy::{get_array_module, AllowTypeChange, PyArrayLike1};

#[pyfunction]
fn sum_up<'py>(py: Python<'py>, array: PyArrayLike1<'py, i32, AllowTypeChange>) -> i32 {
    array.as_array().sum()
}

Python::with_gil(|py| {
    let np = get_array_module(py).unwrap();
    let sum_up = wrap_pyfunction!(sum_up)(py).unwrap();

    py_run!(py, np sum_up, r"assert sum_up((1.5, 2.5)) == 3");
});

Methods from Deref<Target = PyReadonlyArray<'py, T, D>>§

source

pub fn as_array(&self) -> ArrayView<'_, T, D>

Provides an immutable array view of the interior of the NumPy array.

source

pub fn as_slice(&self) -> Result<&[T], NotContiguousError>

Provide an immutable slice view of the interior of the NumPy array if it is contiguous.

source

pub fn get<I>(&self, index: I) -> Option<&T>
where I: NpyIndex<Dim = D>,

Provide an immutable reference to an element of the NumPy array if the index is within bounds.

source

pub fn try_as_matrix<R, C, RStride, CStride>( &self ) -> Option<MatrixView<'_, N, R, C, RStride, CStride>>
where R: Dim, C: Dim, RStride: Dim, CStride: Dim,

Try to convert this array into a nalgebra::MatrixView using the given shape and strides.

Note that nalgebra’s types default to Fortan/column-major standard strides whereas NumPy creates C/row-major strides by default. Furthermore, array views created by slicing into existing arrays will often have non-standard strides.

If you do not fully control the memory layout of a given array, e.g. at your API entry points, it can be useful to opt into nalgebra’s support for dynamic strides, for example

use pyo3::py_run;
use numpy::{get_array_module, PyReadonlyArray2};
use nalgebra::{MatrixView, Const, Dyn};

#[pyfunction]
fn sum_standard_layout<'py>(py: Python<'py>, array: PyReadonlyArray2<'py, f64>) -> Option<f64> {
    let matrix: Option<MatrixView<f64, Const<2>, Const<2>>> = array.try_as_matrix();
    matrix.map(|matrix| matrix.sum())
}

#[pyfunction]
fn sum_dynamic_strides<'py>(py: Python<'py>, array: PyReadonlyArray2<'py, f64>) -> Option<f64> {
    let matrix: Option<MatrixView<f64, Const<2>, Const<2>, Dyn, Dyn>> = array.try_as_matrix();
    matrix.map(|matrix| matrix.sum())
}

Python::with_gil(|py| {
    let np = py.eval("__import__('numpy')", None, None).unwrap();
    let sum_standard_layout = wrap_pyfunction!(sum_standard_layout)(py).unwrap();
    let sum_dynamic_strides = wrap_pyfunction!(sum_dynamic_strides)(py).unwrap();

    py_run!(py, np sum_standard_layout, r"assert sum_standard_layout(np.ones((2, 2), order='F')) == 4.");
    py_run!(py, np sum_standard_layout, r"assert sum_standard_layout(np.ones((2, 2, 2))[:,:,0]) is None");

    py_run!(py, np sum_dynamic_strides, r"assert sum_dynamic_strides(np.ones((2, 2), order='F')) == 4.");
    py_run!(py, np sum_dynamic_strides, r"assert sum_dynamic_strides(np.ones((2, 2, 2))[:,:,0]) == 4.");
});
source

pub fn as_matrix(&self) -> DMatrixView<'_, N, Dyn, Dyn>

Convert this one-dimensional array into a nalgebra::DMatrixView using dynamic strides.

§Panics

Panics if the array has negative strides.

source

pub fn as_matrix(&self) -> DMatrixView<'_, N, Dyn, Dyn>

Convert this two-dimensional array into a nalgebra::DMatrixView using dynamic strides.

§Panics

Panics if the array has negative strides.

Methods from Deref<Target = Bound<'py, PyArray<T, D>>>§

pub fn borrow(&self) -> PyRef<'py, T>

Immutably borrows the value T.

This borrow lasts while the returned [PyRef] exists. Multiple immutable borrows can be taken out at the same time.

For frozen classes, the simpler [get][Self::get] is available.

§Examples
#[pyclass]
struct Foo {
    inner: u8,
}

Python::with_gil(|py| -> PyResult<()> {
    let foo: Bound<'_, Foo> = Bound::new(py, Foo { inner: 73 })?;
    let inner: &u8 = &foo.borrow().inner;

    assert_eq!(*inner, 73);
    Ok(())
})?;
§Panics

Panics if the value is currently mutably borrowed. For a non-panicking variant, use try_borrow.

pub fn borrow_mut(&self) -> PyRefMut<'py, T>
where T: PyClass<Frozen = False>,

Mutably borrows the value T.

This borrow lasts while the returned [PyRefMut] exists.

§Examples
#[pyclass]
struct Foo {
    inner: u8,
}

Python::with_gil(|py| -> PyResult<()> {
    let foo: Bound<'_, Foo> = Bound::new(py, Foo { inner: 73 })?;
    foo.borrow_mut().inner = 35;

    assert_eq!(foo.borrow().inner, 35);
    Ok(())
})?;
§Panics

Panics if the value is currently borrowed. For a non-panicking variant, use try_borrow_mut.

pub fn try_borrow(&self) -> Result<PyRef<'py, T>, PyBorrowError>

Attempts to immutably borrow the value T, returning an error if the value is currently mutably borrowed.

The borrow lasts while the returned [PyRef] exists.

This is the non-panicking variant of borrow.

For frozen classes, the simpler [get][Self::get] is available.

pub fn try_borrow_mut(&self) -> Result<PyRefMut<'py, T>, PyBorrowMutError>
where T: PyClass<Frozen = False>,

Attempts to mutably borrow the value T, returning an error if the value is currently borrowed.

The borrow lasts while the returned [PyRefMut] exists.

This is the non-panicking variant of borrow_mut.

pub fn get(&self) -> &T
where T: PyClass<Frozen = True> + Sync,

Provide an immutable borrow of the value T without acquiring the GIL.

This is available if the class is [frozen][macro@crate::pyclass] and Sync.

§Examples
use std::sync::atomic::{AtomicUsize, Ordering};

#[pyclass(frozen)]
struct FrozenCounter {
    value: AtomicUsize,
}

Python::with_gil(|py| {
    let counter = FrozenCounter { value: AtomicUsize::new(0) };

    let py_counter = Bound::new(py, counter).unwrap();

    py_counter.get().value.fetch_add(1, Ordering::Relaxed);
});

pub fn py(&self) -> Python<'py>

Returns the GIL token associated with this object.

pub fn as_ptr(&self) -> *mut PyObject

Returns the raw FFI pointer represented by self.

§Safety

Callers are responsible for ensuring that the pointer does not outlive self.

The reference is borrowed; callers should not decrease the reference count when they are finished with the pointer.

pub fn as_any(&self) -> &Bound<'py, PyAny>

Helper to cast to Bound<'py, PyAny>.

pub fn as_borrowed<'a>(&'a self) -> Borrowed<'a, 'py, T>

Casts this Bound<T> to a Borrowed<T> smart pointer.

pub fn as_unbound(&self) -> &Py<T>

Removes the connection for this Bound<T> from the GIL, allowing it to cross thread boundaries, without transferring ownership.

pub fn as_gil_ref(&'py self) -> &'py <T as HasPyGilRef>::AsRefTarget
where T: HasPyGilRef,

Casts this Bound<T> as the corresponding “GIL Ref” type.

This is a helper to be used for migration from the deprecated “GIL Refs” API.

Trait Implementations§

source§

impl<'py, T, D, C> Debug for PyArrayLike<'py, T, D, C>
where T: Element + Debug, D: Dimension + Debug, C: Coerce + Debug,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'py, T, D, C> Deref for PyArrayLike<'py, T, D, C>
where T: Element, D: Dimension, C: Coerce,

§

type Target = PyReadonlyArray<'py, T, D>

The resulting type after dereferencing.
source§

fn deref(&self) -> &Self::Target

Dereferences the value.
source§

impl<'py, T, D, C> FromPyObject<'py> for PyArrayLike<'py, T, D, C>
where T: Element + 'py, D: Dimension + 'py, C: Coerce, Vec<T>: FromPyObject<'py>,

source§

fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self>

Extracts Self from the bound smart pointer obj. Read more
§

fn extract(ob: &'py PyAny) -> Result<Self, PyErr>

Extracts Self from the source GIL Ref obj. Read more

Auto Trait Implementations§

§

impl<'py, T, D, C = TypeMustMatch> !RefUnwindSafe for PyArrayLike<'py, T, D, C>

§

impl<'py, T, D, C = TypeMustMatch> !Send for PyArrayLike<'py, T, D, C>

§

impl<'py, T, D, C = TypeMustMatch> !Sync for PyArrayLike<'py, T, D, C>

§

impl<'py, T, D, C> Unpin for PyArrayLike<'py, T, D, C>
where C: Unpin, D: Unpin, T: Unpin,

§

impl<'py, T, D, C> UnwindSafe for PyArrayLike<'py, T, D, C>
where C: UnwindSafe, D: UnwindSafe, T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<'py, T> FromPyObjectBound<'_, 'py> for T
where T: FromPyObject<'py>,

§

fn from_py_object_bound(ob: Borrowed<'_, 'py, PyAny>) -> Result<T, PyErr>

Extracts Self from the bound smart pointer obj. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

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

source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.