21 things I hate about Python

If I had encountered it 10 years ago, I’d be hailing Python as a decent language.

Sadly for Python, though, I met and fell in love with Ruby five years back, and using Python just results in a lot of resentment.

How do I hate python?

Let me count the ways:

1) Blocks are denoted by whitespace. Yeah, everyone complains about
this … and with good reason. Cut-and-paste code from place to place
… and the interpreter yells at you and refuses to run.

2)Classes are bolted on, just like in PERL. Every class method
has to take a first argument of ‘self’. Just like in PERL. Man, my aching fingers.

3) In methods variables aren’t automatically scoped to the
object
. Inside class Dog you have an variable
tail_size. In method Dog.wag() you need to
reference tail_size. Can you just type it? No, you have
to write self.tail_size. This leads to hideously
unreadable code, and premature arthritis.

4) ?: does not exist. Instead of the universal (and concise) text = good ? "good" : "bad", you have to use the awkward and verbose construct text = "good" if "good" else "bad". Ugh.

4.5) The defense that this is “more pythonic”, and in keeping with how the rest of the language syntax works. The analogy that springs to mind is of a person who went on a camping trip and learned to cover his feces with leaves … and has now decided to be consistent and defecate on his living room rug and also cover his scat there with leaves.

5) no && and || – you have to use “and” and “or”. Looks ugly as heck, and mashes up the character space of variables, functions, and logical operators. Blargh.

6) You can’t break statements across lines. You have to use a backslash to continue the line. …as if you’re writing batch files on for MS-DOS in 1981. Even if it’s unambiguously true that a statement is not complete (think “x or …. y”, with y on the second line), it’s an error to try.

7) No public or private keywords to control access to methods inside objects.

8)No pure virtual functions, so if you want to say “dog and cat both inherit from mammal, and each must have a walk() function…you’re SOL.

9) A really ugly mixture of methods and functions. In Ruby, it’s [1,2,3].len, in Python it’s len([1,2,3]). …but that’s not a general rule of thumb – lots of things are methods and lots of other things are functions. There’s no rhyme or reason to it.

10) No automatic typecasting. Want to print out "result == " + result in Ruby? That’s how you do it. In Python, you have to wrap result in str(). Hell, even C++ does this right!!! C++ !!!

11) ugly and verbose iteration: Where Ruby says [1,2,3,4].each { |x| ... }, Python says for x in [1,2,3,4]:.

12) mandatory empty lines to signal the conclusion to a function, class, etc.

13) the ugly “pass” hack : there is, by definition, no such thing as an empty method or function, so if you want one, you have to write out NOOP. What is this, assembly language for a 6502 ?

14) mandatory colons at the end of every line that starts a class or method definition. As best I can tell with out digging up a full Bachus Naur form description of the language, there’s no ambiguous syntax that needs the colon to disambiguate it. Python just sucks.

15) not being in a hash is an error. Say there’s something that might be in a hash, or might not be. Better not just look it up by key – if it’s not there, your program throws an error! So first you’ve got to test for presence. In ruby, you write


result = my_hash[key]

In Python you write

result = None

if key in my_hash:

result = my_hash[key]

21 characters vs. 60.

15.5) calling it a ‘dict’ when everyone else in the word calls association arrays “hashes” these days.

16) arrays have to be sized before using them. In Ruby, you can write a = []; a[12] = 12. In Python that throws an error.

17) The scope rules for giving values to variables in lambdas are wonky. Say you want to create an array of 10 lambdas, the first one of which takes an integer and adds 0 to it and returns the result, the next one which takes an integer and adds 1 to it and returns the result, etc. You’d think that


y = [ None ] * 10

for x in [0, 2 ... 9]:

y[x] = lambda input : input + x

would do the trick, but no: you’ve just created 10 functions that are all identical. They each add 9 to the input.

Why?

Because, to mirror the half-assed block syntax, there’s half-assed scoping behavior. Function definitions bind a variable’s value, but iterators don’t. So you have to write:


def make_lambda(x):

lambda input : input + x

y = [ None ] * 10

for x in [0, 2 ... 9]:

y[x] = make_lambda(x)

See? Because x is now a function argument at the point that it’s used, the write thing happens.

18) all strings are const. Let me say that again: all strings are const. Let’s try it a different way: there is no such thing as a mutable string. If this was some wacky functional language, I’d be down with it: “OK, non-mutable variables is your reason for existence. I get it”. But Python has no excuse. Ints are mutable. Arrays are mutable. …but strings aren’t. Why? Because the design philosophy of this language is “you haven’t been punched in the nuts in 5 minutes ; here, let’s solve that for you!”

19) array.append(). Because the method name .push() is too obvious … and 33% shorter.

7 Responses to “21 things I hate about Python”

  1. Francis W. Porretto Says:

    Sheesh.

    1) C++ for the production of binary executables;
    2) Java for Web applications;
    3) SQL for database work.

    Why use anything else?

  2. Fred Z Says:

    Mr. Turing proved to me once that they’re all the same, so I stopped sweating it. Indeed when feeling biblical, or portentious, I mourn the passing of COBOL, a truly prolix language.

    “Say you want to create an array of 10 lambdas, the first one of which takes an integer and adds 0 to it and returns the result, the next one which takes an integer and adds 1 to it”

    You really must stop eating those mushrooms.

    As for Mr. Porretto’s theories, all versions of C revolt me. I can tolerate Delphi and its versions of Pascal, barely. “Why use anything else?” asks Mr. Porretto. I am easily bored.

    Anyone here old enough to remember Algol and the old Watfor Fortran compiler?

  3. tjic Says:

    [quote comment="227627"]Sheesh.

    1) C++ for the production of binary executables;
    2) Java for Web applications;
    3) SQL for database work.

    Why use anything else?[/quote]

    I’m with you on 1 and 3 (I’m a pretty big fan of C++, although I’m not sure if that speaks to its merits, or just that I’ve got ninja levels of skill at using Templates and am therefore biased to believe that C++ is good).

    I’m not a huge fan of Java. First, there’s a stink of large organization to it. Second, it feels too verbose. Third, I may not know what “downward funargs” are, but I’m pretty sure that I want them. I’m not saying that it’s COBOL. It’s just not lispy like Ruby.

  4. eddie Says:

    [quote comment="227630"]Mr. Turing proved to me once that they’re all the same, so I stopped sweating it. [..] As for Mr. Porretto’s theories, all versions of C revolt me.[/quote]

    One of these things is not like the other.

  5. ngvrnd Says:

    Couple things.

    Yes, the indentation thing was a bad bad choice.

    The colons are hints that a block is starting. I don’t think you can start a block without a colon in python.

    You can split lines if stuff is wrapped in parentheses. This isn’t perfect, and yep it’s another band-aid, sigh.

    “Pythonic” seems to have much in common with another word that ends in “-onic”, but Python’s still way better than Perl or TCL, for example.

    The object system is indeed bolted on. It maketh my brain sad to contemplate it. Lambdas are lame (they can only be composed of a single expression, and not everything in the language is an expression, i.e. if statements don’t return values…). But Ruby has had it’s own share of gaffes in this sort of thing. To Matz’s credit, they’ve generally tried to correct them, vice GvR’s approach where not so much. It’s the Pythonic thing again.

    In re: self — you can work around this using emacs, sort of, but that’s like having little prosthetic fingers on your real fingers. It was a bad choice.

    I think you can set up hashes with default values, it’s just not the default behavior.
    The default value can be “None”, a language token, a singleton representing … nothing.

    But still… python has a lot going for it (it’s significantly more mature than Ruby in some ways, and it has vast tracts of libraries very like unto Perl; it’s better at being an integrated scripting language than Ruby is).

    It’s funny to watch people given the choice between writing something in C++ or python. 99% pick python without a backwards glance, because it’s soooooo much faster to develop in.

    The argument that all languages are equal in the gaze of Professor Turing is one of those true but irrelevant factoids. It’s also true that it’s much easier for humans to get things done in higher-level languages than lower-level ones.

    Comes back to something Whitehead said:

    Civilization advances by extending the number of important operations which we can perform without thinking about them.
    Alfred North Whitehead (1861 – 1947), Introduction to Mathematics (1911)

    And C++ is a crime against humanity. StroustROPE!

  6. Fred Z Says:

    “One of these things is not like the other.”

    Even though they revolt me I don’t ‘sweat’ over them, certainly not enough to write a 19 point criticism. I content myself by mentioning, in passing, that C and all its pussy, plussy, sharpy, little illegitimate offspring begat by the miscegnation of Bell labs and Microsoft have nasty little brackets all over the damn place and overly compressed syntax and nomenclature.

    “begin; do this stuff right here when the dingbat user clicks the wrong button; end;” I can read that.

    Besides, a foolish consistency is the hobgoblin of little minds…, so sayeth Emerson.

  7. melee Says:

    Eh, I read most of these as “it’s not what I’m used to”.