Python Woes – Duck typing

I keep seeing articles on the web that language X is ugly, and that Python is beautiful. While I can’t argue that some languages like PHP or Javascript are pretty much insane in their syntax, I’m somehow reluctant to say that Python is beautiful, or elegant. It is better than Bash or Perl, but that’s how far I will go.

a = 4.0
print a.is_integer()
True
'ha' * a
TypeError: can't multiply sequence by non-int of type 'float'
unichr(a)
TypeError: integer argument expected, got float

One thing that really annoys me in Python is duck typing. Not the idea, mind you, but the way it is implemented by the library: the fact that something walk and quacks like a duck does not mean that you can use it instead of a duck. Exhibit one: I have a variable that claims it is an integer, but I cannot use it as an integer.

The core problem is that the system used in Python for numbers is a total mess. See the is_integer() method I used above? it is only implemented by the type float, so the only way for a callee to check if some number is actually an integer is to call a method that is not defined on integers. Even for numerical types where the return value of is_integer() could actually change, like the new Fraction type introduced in Python 2.6 does not define it. This was supposed to be usable as drop-in replacement for floats.

def foo(x):
  return x % 10 * 4 + x % 15 * 2

The other problem is that Python overload operators in smart ways, this, coupled with duck-typing results in completely non-intuitive behaviour. The function on the side can return the string 'aaaaff'. Still one, would hope that overloading and duck-typing would ensure that the caller would never need to worry about calling the right function because of the type of his data. Wrong. How many Python programmers know that they should use math.fsum instead of sum when adding up float numbers?

sum(['h', 'e', 'l', 'o'], '')
TypeError: sum() can't sum strings [use ''.join(seq) instead]
a = [[1],[2],[3]]
sum(a, [])
[1, 2, 3]

Someone might argue that doing type-checks and dispatch control to the optimal back-end would be prohibitively expensive, so Python cannot do that. But it does, but only to be pedantic about it.

5 thoughts on “Python Woes – Duck typing”

  1. I use sum() for floats all the time. Works fine for me.

    Also, if you need a type check, use type() or isinstance. I’ve been coding in python since 1.4, and have never known about is_integer or the alleged limitations on sum.

    Duck typing “just works” for me.

  2. sum() for floats works, it’s just wrong…

    n = 10000000
    v = float(2 ** 63)

    sum(itertools.chain([v], itertools.repeat(0.1, n))) – v → 0.0
    math.fsum(itertools.chain([v], itertools.repeat(0.1, n))) – v → 999424.0

  3. well, I don’t need floats. I code seriously in python since the 2.4, and if I am mostly pleased with the language itself, but I hate some of the aspects of its CPython implementation. The GIL is a PITA, ducktyping is mostly okay but I think it miss some tools to explicitly constrain type on some vars, list comprehension is ugly, std libs are a mess (not incomplete, but chaotics) etc.

    I still prefer Python to most other languages, but I’d really like to see some sanitization done on it.

  4. @samuel : isinstance is more a part of the introspection support than a part of the duck typing system. In fact, isinstance is almost exactly the opposite : you don’t duck since you explicitly asks for the type of the instance.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.