Flatten... or How to determine sequenceability?

Tim Peters tim.one at home.com
Fri May 25 17:39:53 EDT 2001


[Alex Martelli]
> Hmmm -- good question.  Checking whether x[:] raises an exception
> is reasonable, but a mapping that accepts slice objects would fool
> this test.  I _suspect_ the most-foolproof test today might be:
>
> def is_sequence(x):
>     try:
>         for _ in x:
>             return 1
>         else: return 1    # empty sequences are sequences too
>     except: return 0
>
> However, if I understand correctly, this would break in 2.2,
> since mappings then also become usable in a for statement,
> not just sequences.

Correct, and it's that any iterable object becomes usable in a "for",
including dicts and even files.  However, that also applies in 2.2 to every
other idea you're going to have:

> ...
> What *IS* there that you can do ONLY to a sequence, ANY sequence,
> but NOT to any mapping...?  zip(), which seems like it could serve,
> apparently does NOT test its arguments for "sequencehood"
> (well, depending how you define that, I guess...): it
> does a PySequence_GetItem, and fails iff that fails with
> other than an IndexError.

True today but 2.2 zip() also works with any iterable object(s):

Python 2.2a0 (#16, May 14 2001, 19:54:03) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
>>> d = {1:3, 2:4}
>>> zip(d, d)
[(1, 1), (2, 2)]
>>>

 ...
> I'm almost tempted to propose a tiny extension module, since
> the C-API level *DOES* expose an "is-a-sequence" test...:

This is already available, via the operator.isSequenceType() function (which
just calls PySequence_Check()).  However, again in 2.2,

>>> import operator
>>> operator.isSequenceType({})
1
>>>

dict objects grow a sequence interpretation in 2.2 in order to support
containment testing, i.e. so that you can do

    if key in dict:

instead of

    if dict.has_key(key)

> ...
> ...plus, it ALSO gets thrown by above-exemplified
> object a from class x...!

Yup!  Instances fill in *every* type-object slot, "just in case".

> So, maybe zip IS best after all, something like:
>
> def is_sequence(x):
>     try: zip(x,'')
>     except: return 0
>     else: return 1

This is so clever I'm tempted to revert the 2.2 zip() enhancement <wink>.

> Oh BTW -- all of these methods will see a string or
> unicode object as a 'sequence', because it IS one by
> Python's rules (you can index and slice it, loop on
> it with for, &c).  Most often in such tasks one
> wants to consider strings as atoms, but that will
> require some further special-casing, anyway.

All of which is why Guido is more than half in favor of throwing things like
operator.isSequenceCheck away:  they don't do what people expect them to do,
but then that's because people come to Python expecting stuff like "is a
sequence" to be crisp concepts.  But they aren't in Python, and after
introducing iterable objects, they're even fuzzier.

but-fuzzy-in-a-warm-and-loving-way-ly y'rs  - tim





More information about the Python-list mailing list