You can vectorize the class's __init__ function:

import numpy as np

class Site:
    def __init__(self, a):
        self.a = a
    def set_a(self, new_a):
        self.a = new_a

vSite = np.vectorize(Site)

init_arry = np.arange(9).reshape((3,3))

lattice = np.empty((3,3), dtype=object)
lattice[:,:] = vSite(init_arry)

This may look cleaner but has no performance advantage over your looping solution. The list comprehension answers create an intermediate python list which would cause a performance hit.

Answer from Paul on Stack Overflow
Top answer
1 of 4
32

You can vectorize the class's __init__ function:

import numpy as np

class Site:
    def __init__(self, a):
        self.a = a
    def set_a(self, new_a):
        self.a = new_a

vSite = np.vectorize(Site)

init_arry = np.arange(9).reshape((3,3))

lattice = np.empty((3,3), dtype=object)
lattice[:,:] = vSite(init_arry)

This may look cleaner but has no performance advantage over your looping solution. The list comprehension answers create an intermediate python list which would cause a performance hit.

2 of 4
9

The missing piece for you is that Python treats everything as a reference. (There are some "immutable" objects, strings and numbers and tuples, that are treated more like values.) When you do

lattice[:,:] = site(3)

you are saying "Python: make a new object site, and tell every element of lattice to point to that object." To see that this is really the case, print the array to see that the memory addresses of the objects are all the same:

array([[<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>],
       [<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>],
       [<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>]], dtype=object)

The loop way is one correct way to do it. With numpy arrays, that may be your best option; with Python lists, you could also use a list comprehension:

lattice = [ [Site(i + j) for i in range(3)] for j in range(3) ]

You can use a list comprehension with the numpy.array construction:

lattice = np.array( [ [Site(i + j) for i in range(3)] for j in range(3) ],
                    dtype=object)

Now when you print lattice, it's

array([[<__main__.Site object at 0x1029d53d0>,
        <__main__.Site object at 0x1029d50d0>,
        <__main__.Site object at 0x1029d5390>],
       [<__main__.Site object at 0x1029d5750>,
        <__main__.Site object at 0x1029d57d0>,
        <__main__.Site object at 0x1029d5990>],
       [<__main__.Site object at 0x1029d59d0>,
        <__main__.Site object at 0x1029d5a10>,
        <__main__.Site object at 0x1029d5a50>]], dtype=object)

so you can see that every object in there is unique.

You should also note that "setter" and "getter" methods (e.g., set_a) are un-Pythonic. It's better to set and get attributes directly, and then use the @property decorator if you REALLY need to prevent write access to an attribute.

Also note that it's standard for Python classes to be written using CamelCase, not lowercase.

🌐
NumPy
numpy.org › doc › stable › reference › arrays.html
Array objects — NumPy v2.4 Manual
NumPy provides an N-dimensional array type, the ndarray, which describes a collection of “items” of the same type. The items can be indexed using for example N integers. All ndarrays are homogeneous: every item takes up the same size block of memory, and all blocks are interpreted in exactly ...
🌐
NumPy
numpy.org › devdocs › reference › arrays.html
Array objects — NumPy v2.5.dev0 Manual
NumPy provides an N-dimensional array type, the ndarray, which describes a collection of “items” of the same type. The items can be indexed using for example N integers. All ndarrays are homogeneous: every item takes up the same size block of memory, and all blocks are interpreted in exactly ...
🌐
NumPy
numpy.org › devdocs › reference › generated › numpy.array.html
numpy.array — NumPy v2.6.dev0 Manual
If object is a scalar, a 0-dimensional array containing object is returned. ... The desired data-type for the array. If not given, NumPy will try to use a default dtype that can represent the values (by applying promotion rules when necessary.) ... If True (default), then the array data is copied. If None, a copy will only be made if __array__ returns a copy, if obj is a nested sequence, or if a copy is needed to satisfy any of ...
🌐
Python.org
discuss.python.org › python help
2D NumPy array of objects vs. 2D Python list efficiency - Python Help - Discussions on Python.org
March 9, 2023 - I have a 2D list a of varying shape NumPy arrays and equivalent NumPy array of objects b = np.array(a, dtype='object'). It is inconvenient to slice a, e.g. a[:][1] is not equivalent to b[:, 1], can’t be expressed by slic…
🌐
NumPy
numpy.org › doc › 2.2 › reference › arrays.html
Array objects — NumPy v2.2 Manual
NumPy provides an N-dimensional array type, the ndarray, which describes a collection of “items” of the same type. The items can be indexed using for example N integers. All ndarrays are homogeneous: every item takes up the same size block of memory, and all blocks are interpreted in exactly ...
🌐
Finxter
blog.finxter.com › home › learn python blog › 5 effective ways to create numpy arrays of objects in python
5 Effective Ways to Create NumPy Arrays of Objects in Python - Be on the Right Side of Change
February 20, 2024 - NumPy’s np.array() function is a versatile workhorse for array creation. By specifying the dtype parameter as 'object', NumPy will create an array capable of holding objects, such as Python dictionaries, lists, or even custom classes.
🌐
Scaler
scaler.com › home › topics › numpy › the numpy array object
The NumPy array object - Scaler Topics
May 4, 2023 - The NumPy array object or ndarray, ... as an array when dealing with NumPy. A NumPy array object represents a multidimensional, homogenous array of fixed-size elements....
Find elsewhere
🌐
NumPy
numpy.org › doc › 2.1 › reference › arrays.html
Array objects — NumPy v2.1 Manual
NumPy provides an N-dimensional array type, the ndarray, which describes a collection of “items” of the same type. The items can be indexed using for example N integers. All ndarrays are homogeneous: every item takes up the same size block of memory, and all blocks are interpreted in exactly ...
🌐
SciPy Lecture Notes
scipy-lectures.org › intro › numpy › array_object.html
1.4.1. The NumPy array object — Scipy lecture notes
A slicing operation creates a view on the original array, which is just a way of accessing array data. Thus the original array is not copied in memory. You can use np.may_share_memory() to check if two arrays share the same memory block. Note however, that this uses heuristics and may give you false positives. When modifying the view, the original array is modified as well: ... This behavior can be surprising at first sight… but it allows to save both memory and time. ... NumPy arrays can be indexed with slices, but also with boolean or integer arrays (masks).
🌐
GitHub
github.com › pybind › pybind11 › issues › 647
How to create a numpy array of objects? · Issue #647 · pybind/pybind11
February 6, 2017 - I think I have a partly working solution, adapted from hacking together bits of eigen.h, numpy.h and stl.h: // in type_caster<MyType>::cast array a( npy_format_descriptor<Scalar>::dtype(), // type { (size_t) src.size() } // shape ); for (size_t i = 0; i < src.size(); ++i) { auto value_ = reinterpret_steal<object>(value_conv::cast(src(i), policy, parent)); if (!value_) return handle(); auto p = PyArray_GETPTR1(a.ptr(), i); PyArray_SETITEM(a.ptr(), p, value_.release().ptr()); // steals a reference } return a.release();
Author   pybind
🌐
NumPy
numpy.org › doc › stable › user › basics.creation.html
Array creation — NumPy v2.4 Manual
a list of lists will create a 2D array, further nested lists will create higher-dimensional arrays. In general, any array object is called an ndarray in NumPy.
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.array.html
numpy.array — NumPy v2.4 Manual
If object is a scalar, a 0-dimensional array containing object is returned. ... The desired data-type for the array. If not given, NumPy will try to use a default dtype that can represent the values (by applying promotion rules when necessary.) ... If True (default), then the array data is copied. If None, a copy will only be made if __array__ returns a copy, if obj is a nested sequence, or if a copy is needed to satisfy any of ...
🌐
TutorialsPoint
tutorialspoint.com › numpy › numpy_ndarray_object.htm
NumPy - Ndarray Object
The most important object defined in NumPy is an N-dimensional array type called ndarray. It describes a collection of items of the same type, which can be accessed using a zero-based index.
🌐
NumPy
numpy.org › doc › 2.3 › reference › arrays.html
Array objects — NumPy v2.3 Manual
NumPy provides an N-dimensional array type, the ndarray, which describes a collection of “items” of the same type. The items can be indexed using for example N integers. All ndarrays are homogeneous: every item takes up the same size block of memory, and all blocks are interpreted in exactly ...
🌐
Tician
documen.tician.de › pytools › obj_array.html
Handling numpy Object Arrays - pytools 2025.2.5 documentation
Apply the function f to all entries of the object array ary. Return an object array of the same shape consisting of the return values. If ary is not an object array, return f(ary). ... This function exists because numpy.vectorize suffers from the same issue described under new_1d().
🌐
NumPy
numpy.org › doc › 2.0 › reference › arrays.html
Array objects — NumPy v2.0 Manual
NumPy provides an N-dimensional array type, the ndarray, which describes a collection of “items” of the same type. The items can be indexed using for example N integers. All ndarrays are homogeneous: every item takes up the same size block of memory, and all blocks are interpreted in exactly ...
🌐
Packt
packtpub.com › en-us › learning › how-to-tutorials › numpy-array-object
The NumPy array object
NumPy arrays are typed arrays of fixed size. Python lists are heterogeneous and thus elements of a list may contain any object type, while NumPy arrays are homogenous and can contain object of only one type.
🌐
Scientific-python
lectures.scientific-python.org › intro › numpy › array_object.html
The NumPy array object — Scientific Python Lectures
The default order is 'K'. subok : bool, optional If True, then sub-classes will be passed-through, otherwise the returned array will be forced to be a base-class array (default). ndmin : int, optional Specifies the minimum number of dimensions that the resulting array should have. Ones will be prepended to the shape as needed to meet this requirement. ndmax : int, optional Specifies the maximum number of dimensions to create when inferring shape from nested sequences. By default (ndmax=0), NumPy recurses through all nesting levels (up to the compile-time constant ``NPY_MAXDIMS``). Setting ``ndmax`` stops recursion at the specified depth, preserving deeper nested structures as objects instead of promoting them to higher-dimensional arrays.
🌐
NumPy
numpy.org › doc › stable › reference › generated › numpy.ndarray.html
numpy.ndarray — NumPy v2.4 Manual
An array object represents a multidimensional, homogeneous array of fixed-size items.