On Nov 12, 1:22 pm, Joe Strout <[EMAIL PROTECTED]> 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. -- http://mail.python.org/mailman/listinfo/python-list