correct way to detect container type

R

Robin Becker

I seem often to allow list/tuple arguments to be a singleton. This leads to code
of the form

if type(arg) not in (type(()),type([])): arg = [arg]


or alternatively

from type import ListType, TupleType
_seqTypes = ListType, TupleType
.......
if type(arg) not in _seqTypes: ....

is there a 'best' way to do this?
 
P

Peter Otten

Robin said:
I seem often to allow list/tuple arguments to be a singleton. This leads
to code of the form

if type(arg) not in (type(()),type([])): arg = [arg]


or alternatively

from type import ListType, TupleType
_seqTypes = ListType, TupleType
......
if type(arg) not in _seqTypes: ....

is there a 'best' way to do this?

I prefer

isinstance(var, (list, tuple))

to the above, but I don't think there is one correct way. Often you don't
want a full-blown container, just an iterable. Then

try:
it = iter(var)
except TypeError:
it = iter([var])

may be more appropriate. However, you will end up iterating over the
characters if var is a string, which often has to be guarded against with
an additional isinstance(basestring) test

try:
iter(var)
except TypeError:
var = [var]
else:
if isinstance(var, basestring): var = [var]

Peter
 
C

Carlos Ribeiro

I seem often to allow list/tuple arguments to be a singleton. This leads to code
of the form

if type(arg) not in (type(()),type([])): arg = [arg]

or alternatively

from type import ListType, TupleType
_seqTypes = ListType, TupleType
......
if type(arg) not in _seqTypes: ....

is there a 'best' way to do this?

Depending upon the way you're using your sequence types, why don't you
check for __getitem__? As far as I'm aware, it's all that is needed to
support for loops. In some cases __len__ may also be needed. The
advantage is that you will accept any user defined type that supports
the sequence interface.


--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: (e-mail address removed)
mail: (e-mail address removed)
 
A

Aaron Bingham

Carlos said:
I seem often to allow list/tuple arguments to be a singleton. This leads to code
of the form

if type(arg) not in (type(()),type([])): arg = [arg]

or alternatively

from type import ListType, TupleType
_seqTypes = ListType, TupleType
......
if type(arg) not in _seqTypes: ....

is there a 'best' way to do this?

Depending upon the way you're using your sequence types, why don't you
check for __getitem__? As far as I'm aware, it's all that is needed to
support for loops. In some cases __len__ may also be needed. The
advantage is that you will accept any user defined type that supports
the sequence interface.
Careful! If all you are doing is:

for x in arg:
do something with x

Then arg only needs to support __iter__ and need not be a sequence type
nor support __getitem__.

Aaron
 
T

Tim Williams

Can anyone suggest a way of capturing the output from smtplib's
set_debuglevel into a list or dictionary (or anything else I can work
with), Preferably not to a file, though if this is the only way, then it
would be a start

I have googled.

TIA
 
R

Robin Becker

Peter said:
I prefer

isinstance(var, (list, tuple))

to the above, but I don't think there is one correct way. Often you don't
want a full-blown container, just an iterable. Then

try:
it = iter(var)
except TypeError:
it = iter([var])

may be more appropriate. However, you will end up iterating over the
characters if var is a string, which often has to be guarded against with
an additional isinstance(basestring) test

try:
iter(var)
except TypeError:
var = [var]
else:
if isinstance(var, basestring): var = [var]

Peter
lots of good ideas, but I think this breaks in 2.1 which we're still supporting.
As do some of the iteration ideas.
 
C

Carlos Ribeiro

Peter said:
I prefer

isinstance(var, (list, tuple))

to the above, but I don't think there is one correct way. Often you don't
want a full-blown container, just an iterable. Then

try:
it = iter(var)
except TypeError:
it = iter([var])

may be more appropriate. However, you will end up iterating over the
characters if var is a string, which often has to be guarded against with
an additional isinstance(basestring) test

try:
iter(var)
except TypeError:
var = [var]
else:
if isinstance(var, basestring): var = [var]

Peter
lots of good ideas, but I think this breaks in 2.1 which we're still supporting.
As do some of the iteration ideas.

In 2.1 you can probably use the __getitem__ test.

And I also think that you can define a conditional function in your
library, as to make possible for 2.2+ users to pass iterators. It's a
general solution, and more modern one at that.

I'm now using generators for related things -- namely, when generating
long output, I'm yielding individual strings for each line (or record)
instead of concatenating them into a huge string. Depending on the
system, it will make it more responsive. The performance impact is
negligible; in some scenarios, it's in fact faster, because you can
avoid lots of small string concatenations.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: (e-mail address removed)
mail: (e-mail address removed)
 
S

Steve Holden

Tim said:
Can anyone suggest a way of capturing the output from smtplib's
set_debuglevel into a list or dictionary (or anything else I can work
with), Preferably not to a file, though if this is the only way, then it
would be a start

I have googled.

All smtplib debug output is produced using print statements to standard
ouput, so you could try creating a "file-like" object (such as a
cStringIO) and temporarily replacing sys.stdout with it (saving
sys.sdout and replacing it if other parts of your program need to use it).

If you need help to work out the details, post again.

regards
Steeve
 
A

Andrew Dalke

Tim said:
Can anyone suggest a way of capturing the output from smtplib's
set_debuglevel into a list or dictionary (or anything else I can work
with),

Looking at smtplib.py, all of the debug messages go to
the module variable 'stderr', which is a reference to sys.stderr.

That means you can replace smtplib.stderr with something
of your own. Try this untested bit of code

import cStringIO
old_error = smtplib.error
new_error = cStringIO.StringIO()
try:
smtplib.error = new_error
... do your smtplib call here ...
finally:
smtplib.error = old_error
print "Debug messages"
print new_error.getvalue()

What this does is replace smtplib.error with a StringIO,
which is a file-like object that stays in memory. I used
the try/finally to ensure that the original error output
file is restored after the smtplib call ends.

There are other things you could do by making your own
sufficiently file-like object instead of using StringIO.
All it needs to do is implement the 'write' method.
But it may have to accumulate several writes before it
gets a full line.

class ShowWrites:
def write(self, text):
print "Got", repr(text)

To test it out, change my first example so it uses
ShowWrite instead of StringIO and get rid of the
last two lines

new_error = ShowWrite()

and get rid of these two lines

old_error = smtplib.error
new_error = ShowWrites()
try:
smtplib.error = new_error
... do your smtplib call here ...
finally:
smtplib.error = old_error



Andrew
(e-mail address removed)
 
T

Tim Williams

----- Original Message -----
All smtplib debug output is produced using print statements to standard
ouput, so you could try creating a "file-like" object (such as a
cStringIO) and temporarily replacing sys.stdout with it (saving
sys.sdout and replacing it if other parts of your program need to use it).

If you need help to work out the details, post again.

Many thanks Steve

I have implemented your suggestion , but what is the best way to get the
data out of the file-like object, the only option that seems to work for
me is

f.getvalue()

which returns a string, but getvalue() doesn't "feel" right somehow. Am I
missing something ?

TIA
 
S

Steve Holden

Tim said:
----- Original Message -----



Many thanks Steve

I have implemented your suggestion , but what is the best way to get the
data out of the file-like object, the only option that seems to work for
me is

f.getvalue()

which returns a string, but getvalue() doesn't "feel" right somehow. Am I
missing something ?
If you want to use file primitives to read the value back, just create
another one:

inpt = StringIO.StringIO(firstStringIO.getvalue())

then you can read the printed output from inpt just like a file.

regards
Steve
 
J

Josiah Carlson

If you want to use file primitives to read the value back, just create
another one:

inpt = StringIO.StringIO(firstStringIO.getvalue())

then you can read the printed output from inpt just like a file.

Or even:

firstStringIO.seek(0)

- Josiah
 
T

Tim Williams

----- Original Message -----
Or even:

firstStringIO.seek(0)

- Josiah

Steve, Andrew, Josiah,

Thanks for your answers.

The outgoing SMTP is multi-threaded, so the threads disrupt each other's
output to the file-like object if there is any concurrent outgoing mail
activity.

Is there anyway I can seperate the output from each thread and capture it ?

The outgoing threads are started with
 
P

Peter L Hansen

Tim said:
I have implemented your suggestion , but what is the best way to get the
data out of the file-like object, the only option that seems to work for
me is

f.getvalue()

which returns a string, but getvalue() doesn't "feel" right somehow. Am I
missing something ?

I've never felt the name "spoke to me" very well either :), but
it is the correct way to do it.

Note also, regarding Steve's suggestion, that for simplicity
in a small program you don't need to save sys.stdout if you
are doing that just to restore it later, because sys.__stdout__
is always the original value and a quick sys.stdout == sys.__stdout__
will do the trick.

-Peter
 

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
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top