[Numpy-discussion] __getitem__ and creating an array of objects

Aldcroft, Thomas aldcroft at head.cfa.harvard.edu
Thu May 30 17:31:49 EDT 2013


On Thu, May 30, 2013 at 4:58 PM, Aldcroft, Thomas <
aldcroft at head.cfa.harvard.edu> wrote:

>
>
>
> On Thu, May 30, 2013 at 4:27 PM, Robert Kern <robert.kern at gmail.com>wrote:
>
>> On Thu, May 30, 2013 at 9:21 PM, Aldcroft, Thomas
>> <aldcroft at head.cfa.harvard.edu> wrote:
>> > I'm seeing some behavior that I can't understand when creating a numpy
>> array
>> > of Python objects.  Basically it seems that np.array() is calling the
>> object
>> > __getitem__ method for one object class but not another class, and I
>> can't
>> > understand the difference.
>> >
>> > Here is an example, starting with a simple class where __getitem__ does
>> NOT
>> > get called:
>> >
>> >>>> class Foo(object):
>> > ...     def __getitem__(self, item):
>> > ...         return 1/0
>> > ...     def __len__(self, item):
>> > ...         return 1
>> > ...
>> >>>> f = Foo()
>> >>>> x = np.array([f])
>> >>>> x
>> > array([<__main__.Foo object at 0x11a1ff10>], dtype=object)
>> >
>> > Now move to the complicated class (astropy.time.Time) which has a lot of
>> > stuff in it (including __new__, __init__, and __len__ methods, but
>> initially
>> > no __getitem__), but is otherwise an ordinary class derived from object.
>> > This works as expected:
>> >
>> >>>> from astropy.time import Time
>> >>>> t = Time('2001-01-01', scale='utc')
>> >>>> x = np.array([t])
>> >>>> x
>> > array([2001-01-01 00:00:00.000], dtype=object)
>> >
>> > Now inject a __getitem__ that will fail and try again:
>> >
>> >>>> Time.__getitem__ = lambda self, item: 1 / 0
>> >>>> x = np.array([t])
>> > ERROR: ZeroDivisionError: integer division or modulo by zero
>> >
>> > Any ideas on what is driving this difference in behavior?  BTW, the
>> value of
>> > item in the latter case is 0.
>>
>> What is len(t) in the latter case?
>>
>
> >>> len(t)
> 1
>
> Prompted by this question I looked again at the Foo() definition and see
> that I had copy/pasted the definition of __len__ from __getitem__ and
> forgot to remove the `item` arg.  As written `len(Foo())` would fail.
>  Interestingly, once `Foo.__len__` is valid and succeeds, then
> `f.__getitem__` does indeed get called and `np.array([f])` fails in the
> same way.
>
> Sorry for the noise, though this is still just slightly curious to me.  I
> guess internally maybe there is try/except block that is trying to get a
> len and if that fails then it moves on.
>


Now I realize what seemed curious.  Here is a related example which shows
that when initializing a numpy array of objects where __getitem__ and
__len__ exist, np.array introspects the object item values for item in
range(len(object)) and appears to replace the input object with an ndarray
of the object values.

>>> class Foo(object):
...     attr = 'hello'
...     def __getitem__(self, item):
...         return item
...     def __len__(self):
...         return 5

>>> f = Foo()
>>> f.attr
'hello'

>>> x = np.array([f, f], dtype=object)
>>> x
array([[0, 1, 2, 3, 4],
       [0, 1, 2, 3, 4]], dtype=object)
>>> x[0]
array([0, 1, 2, 3, 4], dtype=object)
>>> type(x[0])
<type 'numpy.ndarray'>
>>> x[0].attr
Traceback (most recent call last):
  File "<ipython-input-16-7b865674a0b6>", line 1, in <module>
    x[0].attr
AttributeError: 'numpy.ndarray' object has no attribute 'attr'

The actual objects that I passed in seem to be lost, which is not the
behavior I expected.

Thanks,
Tom



> - Tom
>
>
>
>>
>> --
>> Robert Kern
>> _______________________________________________
>> NumPy-Discussion mailing list
>> NumPy-Discussion at scipy.org
>> http://mail.scipy.org/mailman/listinfo/numpy-discussion
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20130530/02a4b3a1/attachment.html>


More information about the NumPy-Discussion mailing list