5

For sake of simplicity I've defined a class that is not subclassed from ndarray (for many reasons I find it very complicated), but has an __array__() method that returns a nd.array of a given fixed shape. Let's call this class Foo.

In my script I also generate large lists of Foo instances, and I want to convert them into numpy arrays of arrays. I can easily do it using a map function:

numpy.array(map(lambda x: numpy.array(x), [foo_1, ..., foo_n]))

and it works fine. I was just wondering how I can get things ever more simpler and efficient, and get the following to work:

numpy.array([foo_1, ..., foo_n])

(actually it returns an "error return without exception set"...). It seems that providing an __array__ method is not sufficient to authorize array conversion of lists. Any idea?

2
  • can you include a minimal definition of Foo? is Foo iterable? Other than that, you should re-consider subclassing ndarray... Commented Aug 21, 2014 at 21:09
  • Foo is quite long. The key point is that is has a private attribute which is a 3x3 ndarray. I want Foo instances to behave like this private attribute in some cases, like the above one. Commented Aug 22, 2014 at 6:58

2 Answers 2

3

From the numpy.array docs, the object you pass in must satisfy:

An array, any object exposing the array interface, an object whose __array__ method returns an array, or any (nested) sequence.

You're actually passing in a list of foo objects, so this list doesn't expose the array interface and doesn't have an array method. That leaves only whether it's a nested sequence. To be a nested sequence, your foo objects would likely need to be iterable. Are they? (emulating python's container types)

Not sure if this is any better, but you could probably do:

numpy.array([numpy.array(x) for x in [foo_1, ..., foo_n]])

Here is an example of Foo, as you've described. It outputs the ndarray you'd expect (no exceptions). Hopefully you can use it as an example:

import numpy as np

class Foo(object):
    def __init__(self):
        self.arr = np.array([[1, 2, 3], [4, 5, 6], [7,8,9]], np.int32)

    def __array__(self):
        return self.arr

    def __iter__(self):
        for elem in self.arr:
            yield elem

    def __len__(self):
        return len(self.arr)

    def __getitem__(self, key):
        return self.arr[key]

def main():
    foos = [Foo() for i in range(10)]
    print np.array(foos)


if __name__ == '__main__':
    main()
Sign up to request clarification or add additional context in comments.

3 Comments

Tried to emulate iterable by defining the following methods to Foo: 'iter', 'getitem', 'len','contains', 'add', 'mul','rmul', 'radd', 'contains' methods. They are simply copied from the private attribute which is a 3x3 ndarray. But this did not work either.
@Ssbd78: Not sure if your comment just got name-mangled or not, but did you try the underscore varieties? eg. _____iter_____
@Gerrat: fine! Did not work at first for me because I was too lazy and tried something like: self.__array__ = self.arr.__array__ and so on (taking your example).
0

This will be a bit more efficient and more concise, you don't need the lambda with map:

numpy.array(map(numpy.array,[foo_1, ..., foo_n]))

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.