Bad Python

Update 2012-07-16:  Since this post is still popular 3.5 years later, let me mention that the examples
fall into three general categories of bad practices that really are not specific to Python:

  1. "Bad Python" is often "Old Python": using only the conveniences available in Python before 2.4/2.5. In a fast-moving language, the old ways are often going to look bad.
  2. "Bad Python" is often "Java Python": Python written in Java idioms. It's poor form to write in one language using the idioms of another.
  3. "Bad Python" is often "Bad Programming": many of the practices would be poor form in any programming language.

Original Post
I've seen quite a lot of bad Python, even though Python makes the Path of Good Code relatively easier to find than other languages where spaghetti is the result without extra discipline and years of dedicated study of the language on the part of the programmer. Such is the Tao of Perl.

Much bad Python however is from programmers who only knew statically typed OO languages (Java/C++/C#) and have not yet grokked dynamic typing, first-class functions, pervasive use of iterators, properties, etc, leading to eyesores such as:

  • Accessors such as getDistance() and setDistance(), instead of using an attribute. In Python, attributes can be turned into properties later, preserving the class interface.
  • Asserting the type of every argument and returned value, taking up maybe 30% of the code itself and 80% of the unit test code. Checking is usually pointless because the interpreter itself will let you know if someduck didn't .quack() like a duck, and makes the code less flexible.
  • Uber-private attributes (for no good reason), going so far as to use double-underscores on each side, which are supposed to be reserved for language features.
  • Dozens of customising parameters in constructors, such as reversed and strip and maxlen - when passing in a general transform function would be so much more elegant and could do so much more than just reverse the strings that the class works with.
  • Delegates where first-class function will do.
  • Wrapping things classes when dicts and tuples would be cleaner.
Partly, the developers don't recognise the ways in which many Design Patterns become trivial in Python, to the extent that they are more like one-line idioms than chapter-worthy Patterns with capital "P". Singleton Pattern? Write a module. Iterator? It's fundamental to the language. Need a Factory Pattern? Write a function and thanks to dynamic typing you can substitute makedummywidget for the makewidget during testing.Flyweight objects or Command Dispatch? Just use a dictionary. See also Python Patterns. (correction: previously referred to Abstract Factory, which is is not a factory but a group of related factories, e.g. for widgets from a given UI toolkit). Besides bad habits acquired from static OO, one can write bad code, in any language with
  • Vague and misleading identifiers (topic of future post)
  • Massive 'god' classes
  • Source files having no discernable structure.
  • Awkward decompositions of function
    • Forces similar logic to be repeated in dozens of places
    • Prevents parts from being reused e.g. in unit tests
    • Prevents dependencies from being stubbed out e.g. in unit tests
    • Mixing logic with orthogonal aspects like error-handling and logging for a harder-to-maintain mess.
Oh well. I recently spent a day re-doing about 30% of the functionallity of 8,600 lines of someone elses Java-style Python into 200 lines of real Python to support the greater flexibility I needed. Code can be that bad. (later expanded to just under 300 lines thanks to feature creep) From the comments:

Popular posts from this blog

Cutting down on clutter with the Outbox Method

A comparison of file synchronisation software