Interface and duck typing woes

Terry Reedy tjreedy at udel.edu
Wed Aug 28 17:54:20 EDT 2013


On 8/28/2013 5:09 PM, Joe Junior wrote:
> While designing a simple library, I found myself asking a
> philosophical question: to check or not to check the parameter's
> interface?
>
> I think that, considering it is Python, the usual answer would be
> "no", but here is the situation that got me thinking:
>
> class Flock:
>
>      def __init__(self):
>          self.ducks= []
>
>      def do_stuff(self):
>          for duck in self.ducks:
>              duck.quack()
>
> class Duck:
>
>      def quack(self):
>          #quack-quack
>          pass
>
> f = Flock()
> d = Duck()
> f.ducks.append(d)
> f.do_stuff()
>
> Ok, no big deal there, the problem is if the user forgets to implement
> the quack() method. The stack trace would complain that "duck.quack()"
> is wrong, but that can happen hundreds of lines after the user
> actually added the object to the Flock, and it can be hard to find out
> what is happening and which object is wrong.
>
> Of course I don't want to check isistance(), I like duck typing, but
> should I check if hasattr() and callable() before adding to the
> container? What is the pythonic way to deal with it? Am I worrying too
> much ;-)?

You could underscore '_ducks' and add a .add_duck method with the checks 
you suggest. Or wrap 'duck.quack()' in try-except and log or warn (or 
even raise) on AttributeError or TypeError (not callable) with an 
informative message. Grepping for 'ducks.append(' will find all 
locations where a non-duck might have been added.

Depending on who the users will be, I might just not worry about it 
until an exception is raised. If you try to protect against everything 
that you might do wrong, you are on the road to madness, as the 
protection code might also be buggy. (Too much testing has the same 
problem ;-).

-- 
Terry Jan Reedy




More information about the Python-list mailing list