views:

127

answers:

3

In python is there an easy way to tell if something is not a sequence? I tried to just do: if x is not sequence but python did not like that

+10  A: 

iter(x) will raise a TypeError if x cannot be iterated on -- but that check "accepts" sets and dictionaries, though it "rejects" other non-sequences such as None and numbers.

On the other hands, strings (which most applications want to consider "single items" rather than sequences) are in fact sequences (so, any test, unless specialcased for strings, is going to confirm that they are). So, such simple checks are often not sufficient.

In Python 2.6 and better, abstract base classes were introduced, and among other powerful features they offer more good, systematic support for such "category checking".

>>> import collections
>>> isinstance([], collections.Sequence)
True
>>> isinstance((), collections.Sequence)
True
>>> isinstance(23, collections.Sequence)
False
>>> isinstance('foo', collections.Sequence)
True
>>> isinstance({}, collections.Sequence)
False
>>> isinstance(set(), collections.Sequence)
False

You'll note strings are still considered "a sequence" (since they are), but at least you get dicts and sets out of the way. If you want to exclude strings from your concept of "being sequences", you could use collections.MutableSequence (but that also excludes tuples, which, like strings, are sequences, but are not mutable), or do it explicitly:

import collections

def issequenceforme(obj):
    if isinstance(obj, basestring):
        return False
    return isinstance(obj, collections.Sequence)

Season to taste, and serve hot!-)

Alex Martelli
Note that this code example will return the wrong result for objects that implement the sequence protocol but do not involve the `collections.Sequence` ABC.
Mike Graham
Yep: differently from simpler ABCs, Sequence doesn't implement a `__subclasshook__` class method, so it will never automatically recognize a class that chose not to `register` with it (or inherit from it) -- it would be essentially impossible to tell by introspection whether a class's `__getitem__` accepts integers and slices, raises `IndexError` on wrong indices, etc -- all you need to rule out `dict` and `set`, essentially (that _do_ seem to "implement the sequence protocol" if you just do introspection... but then turn out not to!-).
Alex Martelli
+4  A: 

Why are you doing this? The normal way here is to require a certain type of thing (A sequence or a number or a file-like object, etc.) and then use it without checking anything. In Python, we don't typically use classes to carry semantic information but simply use the methods defined (this is called "duck typing"). We also prefer APIs where we know exactly what to expect; use keyword arguments, preprocessing, or defining another function if you want to change how a function works.

Mike Graham
It's an assignment constraint. If the argument we are passed isn't an int, long or sequence we need to raise a `TypeError`
nicotine
@nicotine, recognize that this assignment indicates a design that is usually nonidiomatic and fragile. Consider the normal case, where an object should be exactly one type of thing. If a parameter is supposed to be a sequence but you get an int, when you index or iterate over it you will already get a `TypeError`. Similarly, if you tried to do integer operations with a sequence you would.
Mike Graham
Providing a consistent API (when at all possible) that expects just one type of thing lets you write simpler code which still raises errors when something goes wrong but is more robust in that it supports types you didn't think about but satisfy the true goal (for example, some custom class that implements `__len__` and `__getitem__` would work as a sequence.)
Mike Graham
+3  A: 

The Python 2.6.5 documentation describes the following sequence types: string, Unicode string, list, tuple, buffer, and xrange.

def isSequence(obj):
    return type(obj) in [str, unicode, list, tuple, buffer, xrange]
David Antaramian
The problem with this answer is that it won't detect sequences that aren't builtin types. A Python "sequence" is any object that implements the methods necessary to respond to sequence operations.
intuited