sufficiently pythonic code for testing type of function

T

Theerasak Photha

I wrote this for someone else to take an object and list of types,
then check if obj is one of those types, raising an error otherwise.

Is it enough to rely on side effects or absence thereof, or should I
put return True in here somewhere?

def test_obj_type(obj, types):
for type in types:
if isinstance(obj, type):
break
else:
raise ValueError, 'object is not in %s' % types

-- Theerasak
 
J

John Machin

Theerasak said:
I wrote this for someone else to take an object and list of types,
then check if obj is one of those types, raising an error otherwise.

Is it enough to rely on side effects or absence thereof, or should I
put return True in here somewhere?

def test_obj_type(obj, types):
for type in types:
if isinstance(obj, type):
break
else:
raise ValueError, 'object is not in %s' % types

Hello Theerasak,

To answer your question: Either (a) return True if OK, False if not OK
or (b) make it like an assertion: raise an exception if not OK, do
nothing if OK. Returning True from the above function would be a rather
strange hybrid.

However:

1. if isinstance(obj, types[1] is true, but isinstance(obj, types[0])
is false, this would appear to raise ValueError. Is the indentation of
the else and raise what you intended?

2. In any case, since Python 2.2, no loop is necessary:

def test_obj_type(obj, types):
if not isinstance(obj, types):
raise ValueError, 'object is not in %s' % (types, )

If you don't want the assertion style, your "someone else" can call
isinstance directly.

3. And please notice the change in the raise line; if types is a tuple
of two or more items, the % operator treats it specially. As coded, you
would get this exception:
"TypeError: not all arguments converted during string formatting"

HTH,
John
 
B

Bruno Desthuilliers

Theerasak said:
I wrote this for someone else to take an object and list of types,
then check if obj is one of those types,

This is already what isinstance(obj, tuple_of_types) does.
raising an error otherwise.

Is it enough to rely on side effects or absence thereof, or should I
put return True in here somewhere?

What for ?
def test_obj_type(obj, types):
for type in types:
if isinstance(obj, type):
break
else:
raise ValueError, 'object is not in %s' % types



def checkinstanceof(obj, types):
if not isinstance(obj, types):
raise ValueError('object is not an instance of %s' % str(types))


Now the real question : what if the object is not an instance of any of
the types, but still support the expected interface ?
 
T

Theerasak Photha

Now the real question : what if the object is not an instance of any of
the types, but still support the expected interface ?

Perhaps:

try:
for attribute in ['foo', 'bar', '__baz__']:
getattr(mystery_object, '__%s__' % attribute)
except AttributeError:
# Do sumthin bout it

Is it wrong to 're-raise' an exception with application-specific
details within an except clause?

-- Theerasak
 
F

Fredrik Lundh

Theerasak said:
Now the real question : what if the object is not an instance of any of
the types, but still support the expected interface ?

Perhaps:

try:
for attribute in ['foo', 'bar', '__baz__']:
getattr(mystery_object, '__%s__' % attribute)
except AttributeError:
# Do sumthin bout it

Is it wrong to 're-raise' an exception with application-specific
details within an except clause?

nope, as long as the new exception is provides more accurate information
about what actually happened. something like

try:
do something
except ValueError:
raise RuntimeError("the frobnitz failed to catch the kitten")

can be a lot better than a 30-level traceback that ends with a line
looking something like

fnut.index(gah)

on the other hand, things like this are all too common:

try:
do something
except:
raise Exception("something happened")

also, checking for __method__ is, in general, not the right way to check
if an object implements a given interface. some types use C-level slots
or alternative hooks to provide functionality, and such things are not
always visible from the outside (Python knows how to use them, though).

so if you can, try doing the operation instead, and catch error (if you
really need to check first, use an idempotent operation, if available).

</F>
 
T

Theerasak Photha

can be a lot better than a 30-level traceback that ends with a line
looking something like

fnut.index(gah)

Despite long experience with Perl, I am not a big follower of the
"goose_level: blah" method of error reporting...
also, checking for __method__ is, in general, not the right way to check
if an object implements a given interface.

I had a vague feeling it might not be a Right Thing(tm).
<flame-proof-underwear>I kind of miss
responds_to? said:
so if you can, try doing the operation instead, and catch error (if you
really need to check first, use an idempotent operation, if available).

I'll do that as soon as my green noggin figures out what 'idempotent' means.

Serves me right for being a liberal arts weenie:
http://www.c2.com/cgi/wiki?ThaiLanguage

-- Theerasak
 
F

Fredrik Lundh

Theerasak said:
I'll do that as soon as my green noggin figures out what 'idempotent' means.

"Acting as if used only once, even if used multiple times", to quote
the first explanation I saw on the google result page.

and from the irony department, googling for "indempotent" provides an
even clearer explanation: "Refers to an operation that produces the same
results no matter how many times it is performed."

</F>
 
B

Bruno Desthuilliers

Theerasak said:
Despite long experience with Perl, I am not a big follower of the
"goose_level: blah" method of error reporting...


I had a vague feeling it might not be a Right Thing(tm).
<flame-proof-underwear>I kind of miss
responds_to?</flame-proof-underwear>

getattr(obj, name[,default]) is your friend. Remember that methods are
just callable attributes.
I'll do that as soon as my green noggin figures out what 'idempotent'
means.

idempotent -> no side effects.
 
A

A.T.Hofkamp

Now the real question : what if the object is not an instance of any of
the types, but still support the expected interface ?

one possible answer: Use ZopeInterfaces
(and ask objects 'do you implement interface X' rather than 'are you type Y')

Not sure what options you have when dealing with builtin data types however.


Albert
 
B

Bruno Desthuilliers

A.T.Hofkamp said:
one possible answer: Use ZopeInterfaces
(and ask objects 'do you implement interface X' rather than 'are you type Y')

Not sure what options you have when dealing with builtin data types however.

This was mostly a rethorical question...
 
B

bruno de chez modulix en face

Theerasak Photha a écrit :
Now the real question : what if the object is not an instance of any of
the types, but still support the expected interface ?

Perhaps:

try:
for attribute in ['foo', 'bar', '__baz__']:
getattr(mystery_object, '__%s__' % attribute)
except AttributeError:
# Do sumthin bout it

Isn't this a case of useless overcomplexification ? Since you end up
raising an exception, why not just assume the object is ok and let
Python raise the exception for you if it is not ? From the client code
POV, it doesn't make much difference !-)

Is it wrong to 're-raise' an exception with application-specific
details within an except clause?

Nope - as long as you provide more details (or more helpful details)
*and* do not loose/mask/whatever useful infos from the original
exception.
 
T

Theerasak Photha

Theerasak said:
Despite long experience with Perl, I am not a big follower of the
"goose_level: blah" method of error reporting...


I had a vague feeling it might not be a Right Thing(tm).
<flame-proof-underwear>I kind of miss
responds_to?</flame-proof-underwear>

getattr(obj, name[,default]) is your friend. Remember that methods are
just callable attributes.

I am familiar with getattr from the Introspection material in Dive
into Python of course.

Earlier in the thread we decided that using getattr is the Wrong
Way(tm) to decide whether an object has such and such operation
(respond_to?) because implementation details can hide this.

So I learned the best thing to do is Suck It And See (an electrical
joke, not a penis joke, BION) aka EAFP.

I just found out Ruby isn't much better in this regard:

class Foo
def self.method_missing(meth, *args)
puts meth
end
end

Foo.bar()
puts Foo.respond_to?:)bar)

===>
bar
false

WTF?

-- Theerasak
 
S

Scott David Daniels

Bruno said:
... idempotent -> no side effects.

Nope. idempotent: f(f(x)) = f(x)
That is, after doing it once, repeating it won't hurt.

--Scott David Daniels
(e-mail address removed)
 

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

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top