I have a list I wrote up once about Python's problems. Some of these are more exotic than others. Most of them are kludgearoundable. A couple are fixed in Python 3. Some are simply design choices that are exactly different from my mental model of the world, and due to the TOOWTDI Python world, it is frustrating to work with them.
Some Things Wrong With Python
* Immutable strings[0]
* Everything a reference[1]
* Environment copied on loop entrance (implying assignments often break when done in loops)
* Lack of braces[2]
* Lack of enums[3]
* Standard debugger pdb reminds me of the first debuggers ( used on the PDP-1 and EDSAC) in its feature list.
* Exception-oriented design, which clutters code with "try/catches" everywhere.
* Exceptions aren't just exceptions, they are also overloaded to provide signals.
* Two forms of objects (old style vs. new-style)
* Object inheritance is pointer to parent. Metaprogramming becomes an exercise in hackery.
* Objects are actually dictionaries with some pointers behind the scenes.
* Duck typing will automagically cast certain things[4]
* As an interpreted language, code that is not tested can be assumed to be syntactically correct but in error (this is a horrible problem when testing for rare error conditions)[4.5]
* When Python is fast, it's because it's calling out to C.
* Python objects are gigantic. An empty string is 40 bytes, for example. This adds up.
* Python can not meaningfully multithread, due to the global interpreter lock.
* Python suffers from many different versions being installed on different versions of Linux[5]
* Lambdas are totally broken[6]
* Large-scale module importing is a half-baked job[7]
* Python 3 routes around some these issues by using generators for everything[8].
[0] Ever try to step through a string and modify it in-memory? Well, you can't. Sorry. ;-)
[1] I.e., a function can modify something unexpectedly.
[2] Which means block commenting or commenting out tops of loops means a complete reindenting of the block, that is, editors can't do the smart thing, they don't have enough context. This is a waste of the engineer's time. Delimiters were figured out in Lisp, a very long time ago.
[3] This was figured out long ago as well.
[4] But not others. Object design is a bit funky.
[4.5] This is a general design 'con' in dynamic languages. It's partially solvable with a sufficiently smart compiler, most compilers aren't that smart.
[5] This is why serious Python programs (that don't come bundled with their own version of Python) are written to target Python 2.4, released in 2004.
[6] A 'lambda' function in Python can not have statements. Most interesting functions have statements.
[7] Python (similar to Java) relies on a very specific directory structure for a given program to be able to import libraries. This means that if you are doing anything remotely exotic with layouts (e.g., libraries are in a peer directory, not a child directory), you have to commit hackery.
[8]This avoids the fact that the end result has to be emitted in some fashion.
Just for the record list comp scoping is fixed in python 3:
$ python3
Python 3.2.1 (default, Aug 1 2011, 14:47:14)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 11
>>> [x for x in [1,2,3]]
[1, 2, 3]
>>> x
11
The problem is not that the argument is mutable, it's that the default argument creation is run at definition time. Mutable arguments are quite useful, and it's consistent to be able to use default arguments in this way; the argument shouldn't outlive the function execution, is all.
I stopped when i found "Lack of braces" in your list.
If you don't like it.. fine.. but it's in my opinion a major plus for python.
Also "everything is a reference" is 1) not true for everything and 2) a smart thing to do. Many languages do that.
Yeah, I goggled a bit at that one too. Particularly when it's immediately followed by a complaint about things being modified unexpectedly.
Some of the complaints are not really issues, eg. you can comment out loops by adding an "if 0:" after commenting out the top line, or else surrounding it with triple quotes """...""".
[5] is an outright lie. Major Python apps support 2.4 onwards, true, but virtualenv (a common piece of Python infrastructure) can support arbitrary libraries and versions of python: http://stackoverflow.com/questions/1534210/use-different-pyt.... And I've never heard of duck typing 'auto casting' anything - code example?
Most of the rest is either a style thing, eg. "lambdas are broken!" (Just define a function first then use it, or use a decorator. You can't write lisp in python), or else broken in other languages too. [4.5] is true for any language, including compiled statically typed languages, not just Python.
Python mixes immutability and mutability in ways that require careful thinking about the problem if you want to write unbuggy code. E.g., does a tuple holding lists allow modification of the member lists? Intuitively, it would seem to me that immutability should cascade, but thinking about tuples as holding a bag of pointers suggests that the lists are still mutable. Anyway.
I generally take the position that if you have to work around something in your language, it's broken. E.g., the virtualenv hack. It's nice to deploy out an exe and not require a whole ecosystem to be install in order to bootstrap it up.
Virtualenv is a pragmatic approach to solve actual problems during both development and deployment. As long as you have a python executable (don't have to be installed system-wide) and the virtualenv.py module, you can create a virtualenv. How is that "a whole ecosystem"?
It is a general rule that no language makes everyone happy all the time. Seeking for the ideal, however, is fine in my books.
I am not into purity in languages, as a personal rule of thumb. I favor Common Lisp for applications, Perl for scripts, and C (or C++) for driver layer code. Those are considered pits of impurity quite often.
Some Things Wrong With Python
* Immutable strings[0]
* Everything a reference[1]
* Environment copied on loop entrance (implying assignments often break when done in loops)
* Lack of braces[2]
* Lack of enums[3]
* Standard debugger pdb reminds me of the first debuggers ( used on the PDP-1 and EDSAC) in its feature list.
* Exception-oriented design, which clutters code with "try/catches" everywhere.
* Exceptions aren't just exceptions, they are also overloaded to provide signals.
* Two forms of objects (old style vs. new-style)
* Object inheritance is pointer to parent. Metaprogramming becomes an exercise in hackery.
* Objects are actually dictionaries with some pointers behind the scenes.
* Duck typing will automagically cast certain things[4]
* As an interpreted language, code that is not tested can be assumed to be syntactically correct but in error (this is a horrible problem when testing for rare error conditions)[4.5]
* When Python is fast, it's because it's calling out to C.
* Python objects are gigantic. An empty string is 40 bytes, for example. This adds up.
* Python can not meaningfully multithread, due to the global interpreter lock.
* Python suffers from many different versions being installed on different versions of Linux[5]
* Lambdas are totally broken[6]
* Large-scale module importing is a half-baked job[7]
* Python 3 routes around some these issues by using generators for everything[8].
[0] Ever try to step through a string and modify it in-memory? Well, you can't. Sorry. ;-)
[1] I.e., a function can modify something unexpectedly.
[2] Which means block commenting or commenting out tops of loops means a complete reindenting of the block, that is, editors can't do the smart thing, they don't have enough context. This is a waste of the engineer's time. Delimiters were figured out in Lisp, a very long time ago.
[3] This was figured out long ago as well.
[4] But not others. Object design is a bit funky.
[4.5] This is a general design 'con' in dynamic languages. It's partially solvable with a sufficiently smart compiler, most compilers aren't that smart.
[5] This is why serious Python programs (that don't come bundled with their own version of Python) are written to target Python 2.4, released in 2004.
[6] A 'lambda' function in Python can not have statements. Most interesting functions have statements.
[7] Python (similar to Java) relies on a very specific directory structure for a given program to be able to import libraries. This means that if you are doing anything remotely exotic with layouts (e.g., libraries are in a peer directory, not a child directory), you have to commit hackery.
[8]This avoids the fact that the end result has to be emitted in some fashion.