How do I test if an object is a sequence?

M

Max M

Is there a common idiom for testing if an object is a sequence?

Both list, tuple and non-standard objects etc. I have Googled, but
didn't find a usable answer.


There are a few direct approaches:


def is_sequence(unknown):
return type(unknown) = type([]) or type(unknown) = type(())

Which is basically the old-school version of:

from types import TupleType, ListType
def is_sequence(unknown):
return isinstance(unknown, (TupleType, ListType))


But they only check for built in objects.

Then there is the approach of testing for a method that they all share.
The only one that springs to mind is the slice operation.

def is_sequence(object)
try:
test = object[0:0]
except:
return False
else:
return True


But it has the disadvantage that string also are sequences. But not
exactly the kind I am interrested in.

So it will need to be expanded to:

from types import StringTypes
def is_sequence(unknown):
if isinstance(unknown, StringTypes):
return False
try:
test = object[0:0]
return True
except:
return False


But that looks kind of ugly for a "simple" type check.

There must be a better way?


regards Max M
 
J

Jp Calderone

Is there a common idiom for testing if an object is a sequence?

Define sequence more thoroughly. I was with your description, up to the
point where you said you didn't think strings qualified. Now I'm not sure
what you're looking for.

For example, do arrays count (array.array)? I guess unicode is out, if
strings are, but what about other kinds of strings (UserString or subclasses
of StringType)?

Or maybe a better question would be this - *why* do you want a function
that returns True when passed a list or a tuple or one of these mysterious
"non-standard objects", but False when passed a string, an integer, or
something else of that variety?

Jp

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)

iD8DBQE/5wCgedcO2BJA+4YRAm0nAJ439nSr0LZjd5e0L5IB7qOYCK9TcACgyhb9
2AUF0Z18+ICiYfso2vkGCeo=
=1qvy
-----END PGP SIGNATURE-----
 
S

Skip Montanaro

Max> Then there is the approach of testing for a method that they all
Max> share. The only one that springs to mind is the slice operation.

Max> def is_sequence(object)
Max> try:
Max> test = object[0:0]
Max> except:
Max> return False
Max> else:
Max> return True

Max> But it has the disadvantage that string also are sequences. But not
Max> exactly the kind I am interrested in.

Max> So it will need to be expanded to:

Max> from types import StringTypes
Max> def is_sequence(unknown):
Max> if isinstance(unknown, StringTypes):
Max> return False
Max> try:
Max> test = object[0:0]
Max> return True
Max> except:
Max> return False

Max> But that looks kind of ugly for a "simple" type check.

Max> There must be a better way?

Not really. You're better off testing for whatever operations you want to
perform. You run the risk of overlapping with mapping objects, but that's
life.

Skip
 
C

Cousin Stanley

| Is there a common idiom for testing if an object is a sequence?
| ....

Max M ....

What about checking against a pre-defined dictionary
of types ???
.... seq_types = { list : 1 , tuple : 1 , dict : 1 }
.... if seq_types.has_key( type( obj ) ) :
.... return True
.... else :
.... return False
....
l = []
t = ()
d = {}
n = 42
s = "Yo Ho Ho and a bottle o' Rum"

isseq( l ) True

isseq( t ) True

isseq( d ) True

isseq( n ) False

isseq( s )
False
 
J

John Roth

Max M said:
Is there a common idiom for testing if an object is a sequence?

Both list, tuple and non-standard objects etc. I have Googled, but
didn't find a usable answer.

The best way I know of is to check for the existance
of either __iter__ or __getitem__. This gets you roughly
the same results as either the for statement or the iter()
built-in function.

John Roth
 
A

Aahz

The best way I know of is to check for the existance of either __iter__
or __getitem__. This gets you roughly the same results as either the
for statement or the iter() built-in function.

Not quite. Try using ``for`` on a dict in Python 2.1 or earlier.
 
J

John Roth

Aahz said:
Not quite. Try using ``for`` on a dict in Python 2.1 or earlier.

Well, yes, but dicts aren't the only problem. The notion of 'sequence'
is sufficiently ill-defined that you almost need to know what the
OP wants to do with it to give a usable answer. For example, do you
want to accept infinite sequences? Some generators will do that to you,
on the other hand, testing for __len__ isn't going to let you accept
files, which are neither infinite nor do they have a usable __len__ or
__getitem__.

And, as you point out, everything that has a __getitem__ and
a __len__ won't accept numeric subscripts. Like dicts.

John Roth

--
Aahz ([email protected]) <*> http://www.pythoncraft.com/

Weinberg's Second Law: If builders built buildings the way programmers wrote
programs, then the first woodpecker that came along would destroy
civilization.
 
L

Lonnie Princehouse

Is there a common idiom for testing if an object is a sequence?

Try iterators...

def is_sequence(thing):
try:
iter(thing)
return True
except TypeError:
return False

Of course, this will return True for strings, but I suspect most
people would say that strings are sequences. You will have
to special-case them.
 
E

EP

Is it possible?

def skeptic(first='Zeus', second='Guido', *others)
print first
print second
print others
return "and I did not think it could ever work!"

answer=skeptic('believer', 'non-believer', 'heretic', first='Eric',
second='unknown')

Asking this seriously, please forgive any cuteness. Is there a way this
can be made to work, or are these two types of arguments mutually exclusive?

TIA,


Eric Pederson
 
F

Francis Avila

EP wrote in message ...
Is it possible?

def skeptic(first='Zeus', second='Guido', *others)
print first
print second
print others
return "and I did not think it could ever work!"

answer=skeptic('believer', 'non-believer', 'heretic', first='Eric',
second='unknown')

Asking this seriously, please forgive any cuteness. Is there a way this
can be made to work, or are these two types of arguments mutually
exclusive?

This particular case seems to be theoretically possible but the
implementation can't handle it. Enter a feature request. You may end up
having to write a PEP if this is deemed a change of semantics, and it may
very well be.

I think there's a deeper issue here: you want Python to assign default args
first, then fill in positional arguments, skipping over those already
assigned. Python wants all arguments to be assigned positionally, and then
to have keyword arguments assigned at the end (with the result that in
certain combinations of calls and default arguments, things get assigned
twice; hence your error.)

And Python wants this for a very good reason: it's a far clearer and simpler
specification. If you assign keyword arguments first, then positional, you
have to do all sorts of magic to figure out what the programmer really
means; and it may get it wrong, which means the programmer has to figure out
what *Python* expects, and hence has to sort through a complex spec. In
programming languages, to strive for DWIM will always give us perl. If DWIM
isn't right 99.9% of the time, it's far more confusing than giving a simple,
consistent spec, to which the programmer conforms. The simple reason for
this is that people are far more adaptable than computers, and the onerous
is always on us, in the end, to learn to use a language. So would you
rather learn a simple language, or a complex one? A DWIM language will
inevitably be complex.

Of course, you can take this to the opposite extreme, in which we have
Forth, Lisp/Scheme, and assembly. :)

So the issue isn't the optional arguments (the '*others') at all. For
example, should the following be allowed?

def g(a=1, b): return a,b

Should you be able to call it like this:

g(2, a=9)

and get (9, 2)? From what you say, you're leaning towards 'yes'. Python,
however, says explicitly, 'no', in section 7.5 of the language reference.
"If a parameter has a default value, all following parameters must also have
a default value." I could even argue that *allowing* you to have a tuple
argument after keyword arguments is a violation of the specs. As usual, the
specs aren't the clearest or most unambiguous, and we need to go by the
reference implementation.

IMO, I think what you propose is a bit confusing. The function must assume
that if default arguments are specified explicitly, then they must be
ignored as positional.

Let's do a thought experiment:

def f(a=1, b=2, *c): return a,b,c

f(9) # Whose argument is this, a or c?
-> (9, 2, ()) #Python says a's. So it interprets as positional.
f(b=9)
-> (1, 9, ())
f(a=1, 2,3,4) # Does 2 belong to b or to c?
-> SyntaxError # Python resists the urge to guess. 'import this'
f(2,3,4, a=1) # Does 2 belong to a, to b, or to c?
-> TypeError #Python says, to 'a'. And trips over itself. But true question
remains unanswered.

Here's a real toughie:

f(2,3,4,b=1) # To whom does 2, 3, and 4 belong?

You already know what Python says, but I bet you're not sure what *you*
would say, nor what some other programmer would say. So you now see the
Python philosophy quite clearly: you may not like what Python does, but you
certainly understand it unambiguously!

Your scenario of f(3,4, a=1, b=2) is the only one where an unambiguous
answer is conceivably possible. But if Python allows the semantics you
prefer, it will complicate the implementation and the specification, and
further it will encourage this sort of behavior, leading to the scary
possibility of a future PEP that suggests that f(2,3,4,b=1) have a legal
interpretation, too!

You should be happy enough that we have default and keyword arguments at
all: they are a tradeoff between convenience and simplicity/explicitness. I
think Python has achieved the right balance here, and we shouldn't ask too
much, lest we regret our asking.
 
D

David Eppstein

def skeptic(first='Zeus', second='Guido', *others)
print first
print second
print others
return "and I did not think it could ever work!"
[/QUOTE]

I think there is not so much problem mixing keyword=something and
*unknownqty, as long as you do not also allow named positional arguments.

def skeptic(*others, **keywords):
print keywords['first']
print keywords['second']
print others
return "and I did not think it could ever work!"
second='unknown')
Eric
unknown
('believer', 'non-believer', 'heretic')'and I did not think it could ever work!'
 
S

Simon Burton

Is there a common idiom for testing if an object is a sequence?

Both list, tuple and non-standard objects etc. I have Googled, but didn't
find a usable answer.


There are a few direct approaches:


def is_sequence(unknown):
return type(unknown) = type([]) or type(unknown) = type(())

return type(unknown) in (list,tuple)

this works in python 2.2 for me. I don't use a function for it tho.

Simon Burton.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,173
Messages
2,570,937
Members
47,481
Latest member
ElviraDoug

Latest Threads

Top