duck-type-checking?

pruebauno at latinmail.com pruebauno at latinmail.com
Wed Nov 12 13:48:21 EST 2008


On Nov 12, 1:22 pm, Joe Strout <j... at strout.net> wrote:
> On Nov 12, 2008, at 10:45 AM, Tim Rowe wrote:
>
> > What do you actually mean by "Quacks like a string"? Supports the
> > 'count()' method? Then you find out if it doesn't when you try to
> > apply the 'count()' method. Supports some method that you don't
> > actually use? Then why do you care?
>
> Because if I write a method with the intention of treating the
> arguments like strings in various ways (slicing, combining with other
> strings, printing to stdout or writing to a file, etc. etc.), and some
> idiot (i.e. me six weeks later or long after I should have gone to
> bed) manages to accidentally pass in something else, then I want my
> program to blow up right away, not plant a roadside bomb and
> cheerfully wait for me to drive by.
>
> This is not hypothetical -- just last week I had a hard-to-track-down
> abend that ultimately turned out to be an NLTK.Tree object stored
> someplace that I expected to only contain strings.  I found it by
> littering my code with assertions of the form
> isinstance(foo,basestring).  If I'd had those in there in the first
> place, not only documenting my assumptions but letting the computer
> check them for me, it would have saved me a lot of grief.
>
> But in the spirit of duck-typing, I shouldn't actually check that foo
> is a basestring.  I should instead check that foo quacks like a
> basestring.  I'd define that is:
>
> "x quacks like a basestring if it implements all the public methods of
> basestring, and can be used in pretty much any context that a
> basestring can."
>
> I have to say "pretty much" since obviously there may be some evil
> context that actually checks isinstance.  But that's the pathological
> case, and we shouldn't let it prevent us from neatly handling the
> typical case.
>
> > The point about duck typing is that something might quack like a duck
> > but not walk like a duck -- one of those duck calls that hunters use,
> > for instance. Quacking like a duck doesn't actually mean it /is/ a
> > duck, it means that it will do instead of a duck if the quack is all
> > you want.
>
> Well, that's one point, but it's not the only point.  If I have code
> that expects to be working with strings, and I want to purposely give
> it something else, then it's reasonable to expect that the something-
> else will act like a string in every way that a string is likely to be
> exercised.  My string wrapper or doppleganger_string or whatever
> should implement all the methods, and support all the operators and
> type conversions, that basestring does.
>
> > If you need to know that it walks like a duck, mates like a duck and
> > tastes like a duck when roasted, you probably want it to really /be/ a
> > duck and should go back to inheritance.
>
> I can't agree; there are times when inheritance just won't do, for
> example when you don't have control over the object creation, because
> they come from some factory method you can't change.  In that case you
> may need to make a wrapper instead of a subclass, but if you've
> faithfully implemented the interface of the original class, you should
> be able to use it wherever the original class could be used (within
> reason).
>
> So, since it's pretty clear by now that there's no standard idiom for
> this, I'll try to cook up something myself.  For classes, I think we
> could do a two-stage test:
>
> 1. If the given object isinstance of the specified class, then all is
> good and return immediately.
> 2. Otherwise, check each of the public attributes of the specified
> class, and make sure that the given object has corresponding callable
> attributes.
>
> For case 2, we might be able to cache the result so that we don't do
> all that work again the next time the same type comparison is done.
>
> Anyway, I'll evolve something in our shop here and live with it a
> while, and in a few months I'll either share what we develop for this
> purpose, or admit it was a horrible idea all along.  :)
>
> Cheers,
> - Joe

It seems to me that what you are describing is exactly what abcs were
added for in 2.6, in particular registration:

class AnotherClass(metaclass=ABCMeta):
    pass
AnotherClass.register(basestring)

assert isinstance(str, AnotherClass)

Please read this first:
http://www.python.org/dev/peps/pep-3119/

and tell us why that would not work.



More information about the Python-list mailing list