scalar types should not be iterable.
The following code should fail but actually print 6 empty list on pypy.
import numpy as np
print(list(np.int8(17)))
print(list(np.int16(17)))
print(list(np.int32(17)))
print(list(np.int64(17)))
print(list(np.float32(17)))
print(list(np.float64(17)))
Comments (11)
-
reporter -
reporter Actually, after looking at the
np.generic
class, I don't really understand why it is not iterable in cpython since it has the__getitem__
method. Is there some tricks in cpython (c level?) to make a object with__getitem__
not iterable? -
@yuyichao Quoting from the doc: "object must be a collection object which supports the iteration protocol (the
__iter__()
method), or it must support the sequence protocol (the__getitem__()
method with integer arguments starting at 0)." As these types raiseIndexError
s with index 0, they are not iterables. -
reporter @lilydjwg raising
IndexError
with index0
does not make them not-iterable. The following code runs fine on all python versions I can find (cpython
/pypy
, 2/3)class A: def __getitem__(self, key): raise IndexError list(A())
-
reporter P.S.
str
object in python2 does not have__iter__
method but a0
-lengthstr
is still iterable. -
Oops, I was wrong.
In
PyObject_GetIter
, if__iter__
is not defined, it callsPySequence_Check
, which then checks the.tp_as_sequence
field of the type. This isNULL
fornumpy.generic
(it has the.tp_as_mapping
field to provide__getitem__
). -
reporter So it is indeed a feature of the cpython c-api The best workarround I can think of so far is to add the following method to
numpy.generic
@classmethod def __iter__(cls): raise TypeError("'%s.%s' object is not iterable" % (cls.__module__, cls.__name__))
However, this will make
isinstance(numpy.int32(1), collections.Iterable)
True
...... -
In Python code, when
__getitem__
is defined, when the class is instanticated, it callstype_call
inObjects/typeobject.c
. It assigns the address ofas_sequence
of aPyHeapTypeObject
to the class'stp_as_sequence
field. ThePySequenceMethods
struct it points to is initially all zeros, sotp_as_sequence->sq_item
isNULL
. Then, inupdate_one_slot
called fromfixup_slot_dispatchers
called fromtype_new
as the type'stp_new
field called fromtype_call
, it checks if__getitem__
is defined. If that is true, it assigns theslot_sq_item
function totp_as_sequence->sq_item
, to makePySequence_Check
returnTrue
. -
There is no way in Python, according to the language spec, to have an object with
__getitem__
which is not iterable. I suppose that numpy implements that by obscure hacking at the C level. Yichao's is the only workaround. I don't think thatcollections.Iterable
is a big blocker... -
reporter LOL.
I guess being
collections.Iterable
is indeed fine since it is already confusing enough and an object with__getitem__
is technically "iterable" anyway.... -
reporter - changed status to resolved
Fixed
- Log in to comment
tested with pypy 2.4.0-alpha0 from ArchLinux Official repo and numpy master