Object type check

Steven D'Aprano steve at REMOVEME.cybersource.com.au
Wed Feb 7 19:28:35 EST 2007


On Wed, 07 Feb 2007 08:59:12 -0800, king kikapu wrote:

> I see what you mean by "duck typing". So you suggest the "do nothing
> at all" direction,
> better document my code so other can see what is expected, right ?

Generally speaking, yes, but not always.

The usual Python model is "better to ask forgiveness than permission". For
example, these two snippets of code do (more or less) the same thing, but
the second is more in the Pythonic style:


# Look Before You Leap
if isinstance(x, SomeClass):
    x.somemethod()
else:
    do_something_else()

# Better To Ask For Forgiveness Than Permission
try:
    x.somemethod()
except AttributeError: # no such method exists
    do_something_else()


Setting up a try...except block is cheap in Python, so it costs very
little to try calling the method, then take a different action only if it
is one of the rare failures. (However, catching the exception is
expensive, so if you have lots of failures, you might want to rethink your
strategy.)

But sometimes this isn't what you want. Here's a counter example:

def modify(list_of_x):
    for x in list_of_x:
        x.change_in_place()

Note that there's no "do_something_else" to do if an item doesn't have
the correct method. That's bad data, and no recovery is possible, so
you just let the exception propagate. But there's a problem: if the
calling code catches the exception, as it may, you leave the list_of_x
in an intermediate state where some of the items have been changed and
some haven't. 

The solution is a form of Look Before You Leap that doesn't break
duck-typing:

def modify(list_of_x):
    for x in list_of_x:
        try:
            x.change_in_place  # don't call the method, just check it exists
            # we can check as many or as few methods as we need, e.g.: 
            x.__getitem__ # check that x is indexable
        except AttributeError:
            raise ValueError("list contains an invalid item")
    # if we get here, we know it is safe to proceed
    for x in list_of_x:
        x.change_in_place()

Now each item doesn't have to be an instance of SomeClass, but merely
needs to have the right signature.


-- 
Steven D'Aprano 




More information about the Python-list mailing list