np.frompyfunc
кажется самым удобным и быстрым инструментом для манипулирования массивами объектов пользовательских классов. Это может быть в два раза быстрее, чем понимание списка (не так уж много выгоды), и обрабатывает вещание.
Ваш класс с небольшим улучшением:
In [418]: class Foo():
...: def __init__(self, val):
...: self.attribute = val
...: def __repr__(self):
...: return f'<Foo> {self.attribute}'
...:
In [419]: Foo(1)
Out[419]: <Foo> 1
Простое понимание списка - не плохой путь к go:
In [420]: alist = [Foo(i) for i in range(5)]
In [421]: alist
Out[421]: [<Foo> 0, <Foo> 1, <Foo> 2, <Foo> 3, <Foo> 4]
In [422]: arr = np.array(alist)
In [423]: arr
Out[423]: array([<Foo> 0, <Foo> 1, <Foo> 2, <Foo> 3, <Foo> 4], dtype=object)
эквивалентно frompyfunc
. Я определил __init__
для аргумента, чтобы я мог передать ему значение. Это можно изменить:
In [424]: arr = np.frompyfunc(Foo,1,1)(range(5))
In [425]: arr
Out[425]: array([<Foo> 0, <Foo> 1, <Foo> 2, <Foo> 3, <Foo> 4], dtype=object)
Выборка значений:
In [426]: np.frompyfunc(lambda f: f.attribute,1,1)(arr)
Out[426]: array([0, 1, 2, 3, 4], dtype=object)
Изменение значений (нельзя сделать это с лямбдой):
In [427]: def setfoo(foo, val):
...: foo.attribute = val
...:
In [428]: np.frompyfunc(setfoo,2,0)
Out[428]: <ufunc '? (vectorized)'>
In [429]: _(arr, [10,np.ones((3,2)),np.arange(3),None, 'foobar'])
Out[429]: ()
In [430]: arr
Out[430]:
array([<Foo> 10, <Foo> [[1. 1.]
[1. 1.]
[1. 1.]], <Foo> [0 1 2],
<Foo> None, <Foo> foobar], dtype=object)
A 2d создание массива:
In [432]: M = np.frompyfunc(lambda i,j: Foo((i,j)), 2,1)(*np.ix_([1,2,3],[10,20]))
In [433]: M
Out[433]:
array([[<Foo> (1, 10), <Foo> (1, 20)],
[<Foo> (2, 10), <Foo> (2, 20)],
[<Foo> (3, 10), <Foo> (3, 20)]], dtype=object)