On Thu, 13 Nov 2008 13:11:12 -0800, George Sakkis wrote: > On Nov 13, 10:15 am, Joe Strout <[EMAIL PROTECTED]> wrote: >> On Nov 12, 2008, at 7:32 PM, Steven D'Aprano wrote: >> >> > While the recipe is great, it can be tiresome to apply all the time. >> > I would factor out the checks into a function, something like this: >> >> > def isstringlike(obj, methods=None): >> > """Return True if obj is sufficiently string-like.""" if >> > isinstance(obj, basestring): >> > return True >> > if methods is None: >> > methods = ['upper', 'lower', '__len__', '__getitem__'] >> > for method in methods: >> > if not hasattr(obj, method): >> > return False >> > # To really be string-like, the following test should pass. if >> > len(obj) > 0: >> > s = obj[0] >> > if s[0] != s: >> > return False >> > return True >> >> Thanks for this, too; that's the sort of method I had in mind. That >> last test for string-likeness is particularly clever. I'll need to >> think more deeply about the implications. > > To me this seems it combines the worst of both worlds: the explicitness > of LBYL with the heuristic nature of duck typing.. might as well call it > "doyoufeellucky typing". If you are going to Look Before You Leap, try > to stick to isinstance/issubclass checks (especially in 2.6+ that they > can be overriden) instead of crafting ad- hoc rules of what makes an > object be X-like.
That's crazy talk. Duck-typing is, at it's very nature, ad-hoc. You want something that is just duck-like enough for your application, without caring if it is an honest-to-goodness duck. "Duck-like" depends on the specific application, in fact the specific *function*. You can't get any more ad-hoc than that. What I posted, taken from Alex Martelli, is duck-typing. It's just that the duck-type checks are performed before any other work is done. The isinstance check at the start of the function was merely an optimization. I didn't think I needed to say so explicitly, it should have been obvious. Take this example: def foo(alist): alist.sort() alist.append(5) The argument can be any object with sort and append methods (assumed to act in place). But what happens if you pass it an object with a sort method but no append? The exception doesn't occur until *after* the object is sorted, which leaves it in an inconsistent state. This can be undesirable: you might need the function foo to be atomic, either the entire function succeeds, or none of it. Duck-typing is great, but sometimes "if it walks like a duck and quacks like a duck it might as well be a duck" is not enough. Once you've built an expensive gold-plated duck pond, you *don't* want your "duck" to sink straight to the bottom of the pond and drown the first time you put it on the water. You want to find out that it can swim like a duck *before* building the pond. -- Steven -- http://mail.python.org/mailman/listinfo/python-list