Comment Re:Adventures in duck-typing (Score 1) 311
What you describe (that names are merely labels attached to objects) is more or less right, but doesn't capture what duck typing is.
Duck typing is summed up neatly by contrasting two principles: LBYL (look before you leap) and EAFP (easier to ask forgiveness than permission). These catchy phrases nicely capture two different methods. Consider these examples (numbered 1 through 4):
def square(value):
.. if type(value) != int:
..... raise ValueError('Argument must be an int')
.. return value**2
def square(value):
.. if isinstance(value, int):
..... raise ValueError('Argument must be an int')
.. return value**2
def square(value):
.. try:
..... return value**2
.. except TypeError:
..... raise ValueError('Invalid value passed')
def square(value):
.. return value**2
(Sorry about the prepended dots, but Slashdot's ecode tag is lame.
If you're used to statically typed languages, you may gravitate to the first two examples, but this is unpythonic. This tests that the type of the value passed is what you expect, and in doing so, prevents duck typing, because you can't pass it an object that acts like an int. (The second one is slightly better than the first, in that it will allow other objects so long as they are subclassed from int.)
The third example is better still, but why bother catching the exception at all? In doing so, you're passing less information in the exception than if you'd just done nothing at all, which is what example 4 does. Example 4 is pythonic: it allows duck typing (anything that supports __pow__ can be passed), and if the value is invalid, the TypeError exception automatically raised will be informative.