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:
- "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.
- "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.
- "Bad Python" is often "Bad Programming": many of the practices would be poor form in any programming language.
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.
- 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.