Inspired by Titus (who was in turn inspired by brian d foy), here’s what I hate about Python. I completely agree with Brian that you can’t trust any advocate who doesn’t know enough to find stuff to hate. Given that I spend a lot of time advocating Python, writing down what I hate seems a good exercise. Perhaps I’ll do the same for Django in the future…
Anyway, here are the five things I hate about Python, presented Letterman-style:
5. Where are my interfaces?
I’m pretty convinced that every piece of software has at least one good idea. Even the steaming hunk of crap that we call “Java” has one: interfaces.
Now, I’m pretty convinced that Python strikes a great balance between expressiveness and minimalism; I can do nearly everything I want with the small set of built-in types. However, the one thing I can’t effectively do is codify a set of behaviors into an interface. There are a number of third-party libraries that implement interfaces (PyProtocols, zope.interface), but they feel “clunky” compared to what first-class interfaces would solve. It seems to me that interfaces are a perfect match to duck typing; I shouldn’t need to care care about the difference between something that pretends to be a list and something that really is a list.
4. What the hell is a list, anyway?
I think this next one follows naturally out of the above. Many, many functions are documented as operating on “list-like” or “file-like” or “dict-like” objects, but there’s a general lack of agreement about what exactly constitutes a minimal interface for any of these objects. Is something that supports read() and write() enough to be a “file,” or is seek() a necessity, too?
Does a list just need to implement __getitem__, or is __len__ required? I could go on and on.
This has real — and sometimes nasty — repercussions: the HttpResponse object in Django implements (our idea of) a minimal file interface, and so much of the time you can pass one in anywhere you’d normally use a file. However, some libraries with different ideas of “file-ness” will break when handed an HttpResponse (for a while reportlab wouldn’t handle an HttpResponse; I forget what we had to add to make that work).
Python 3000 supposedly will solve this with the use of ABCs (Abstract Base Classes); that’s OK, but I’d still rather see interfaces.
3. Concurrency is is really really hard hard
Concurrency in Python sucks balls.
Threading is slow because of the GIL and hard because the built-in threading module is rudimentary (at best).
Coroutines/microthreads are only supported if you want to experiment with Stackless.
If you want asyncronous IO you’ve basically got two shitty options: the standard library asyncore module (which is far too low-level and rudimentary to be considered “easy”), and Twisted which is huge and chronically under-documented.
2. Egg on my face
OK, they’re only really a de facto part of Python, but I’m still gonna bitch about Eggs: I freeking hate them.
Sure, easy_install Something is quite awesome, but I couldn’t be more unhappy about how that actually works. I could bitch for ages about ‘em, but I’ll just point out the two big things I can’t stand:
First, Have you ever looked at sys.path with a couple of eggs installed? Here’s a bit of mine:
... '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/setuptools-0.6c3-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/mechanize-0.1.6b.dev_r36082-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/ClientForm-0.2.6.dev_r36070-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/geopy-0.93-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/kid-0.9.4-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/elementtree-1.2.6_20050316-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/Unipath-0.1.0-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/PyYAML-3.04-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/simplejson-1.5-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/Paste-1.2.1-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/selector-0.8.11-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/resolver-0.2-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/wsgiref-0.1.2-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/svnshelve-0.1-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/paramiko-1.7-py2.4.egg', '/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/pycrypto-2.0.1-py2.4-macosx-10.3-fat.egg', ...
That’s right: each egg gets its own entry on sys.path. This is bad because of the way Python’s import mechanism works; importing a package makes around ten different open syscalls for each entry on sys.path; that is, import foo looks for:
- foo.so
- foomodule.so
- foo.py
- foo.pyc
- foo.pyo
- foo/__init__.so
- foo/__init__module.so
- foo/__init__.py
- foo/__init__.pyc
- foo/__init__.pyo
Multiply that by 10 or 20 or however many eggs you’ve got and you’re actually talking serious import overhead here.
Second — and more distressing to me — is the fact that eggs get in the way of viewing source. Packages installed from eggs are installed as ZIP files; this means that viewing their source requires unpacking the egg. Yes, this is a bit trivial, but newbies to Python aren’t even going to know how to do this! I’ve talked to a number of first-time Python people who assume that CheeseShop packages are closed-source in some way.
You can fix this, by the way, with these lines in ~/.pydistutils.cfg:
[easy_install] zip_ok = false
But that’s a hack, really.
1. Whose standards are these, anyway?
Finally, we come to the standard library.
I should say off the top that for many, many uses the standard library is awesome. The concept of “batteries included” is fantastic, and the particular batteries that Python includes are for the most part amazing. I feel comfortable critcizing the standard library precisely because it’s so good — with a minimal amount of work, it could be even better.
Titus covered the problems of inconsistancy and spotty documentation pretty well, so I’ll focus on my specific concern: what exactly is considered “standard”, anyway?
There’s a whole set of libraries out there that I basically consider required to get any real work done, but aren’t included in the standard library. A (partial) list would include:
Python would be about 100% more useful if the standard library included more packages that people actually consider “standard”.
Update:
Fixed the spelling of brian d foy’s name. Sorry!
Jim
March 4th, 2007
5:09 p.m.
I think everybody agrees with #1. What I really don't understand is xml.etree. The Python manual has next to no documentation, you have to go to the original homepage for it to get more useful stuff (and even that is badly laid out and lacking).
On the other hand, lxml, which provides a compatible interface, is *much* more complete, and has much better documentation. For instance, I find it hard to believe that most people who want xpath aren't interested in attributes, butthat's something elementtree doesn't bother with.
How come elementtree made it into the stdlib and lxml didn't?
James
March 4th, 2007
5:42 p.m.
http://www.parallelpython.com/ is another way to get concurrency, although targetted at multiple core/cpu/machine scaling.
Bill de hOra
March 4th, 2007
5:56 p.m.
"Even the steaming hunk of crap that we call 'Java' has one: interfaces."
In one very important way Java interfaces suck. You can't extend them after the fact without breaking all implementations. Abstract classes don't have this problem and might be closer to what you're looking for (btw what zope provides, bless it, is closer to an abstract class). C# avoided pure interfaces.
"Coroutines/microthreads are only supported if you want to experiment with Stackless."
EVE Online runs on stackless - http://www.eve-online.com/faq/faq_07.asp. They seem to think Python was not viable for them without it. There's a great presentation they gave on this; I'll mail you a link when I can find it.
If we all run off and use something else it'll be because of concurrency. The GIL makes me want to drink a heck of a lot of rum. There's way more to it than "threads suck".
"http://www.crummy.com/software/BeautifulSoup/"
I wouldn't like to see this in the standard library - yet. I think it might have some unicode bugs.
Tim
March 4th, 2007
6:29 p.m.
Numeric has been superseded (obsoleted?) by numpy (It appears that many people are not aware of this.)
jmlai
March 4th, 2007
6:39 p.m.
I agree with all those, although #1 is a bit more controversial because, as you said, different people have their own ideas of what's standard. (What's up with those audio libraries anyway?) Also, you effectively tie releases of the library to releases of Python -- it's harder to say "you need a new version of XYZ from pyXYZ.org" when it's already in the standard library.
Jacob
March 4th, 2007
6:49 p.m.
@Jim: exactly :)
@Bill: Yes, I've seen the EVE presentation (at PyCon, last year [IIRC]). There's something that rubs me the wrong way about "if you want concurrency, install this unofficial, patched version of Python."
@James: PP doesn't really solve concurrency; it's really just an IPC mechanism, which is always going to be more heavyweight than real concurrency.
Doug
March 4th, 2007
7:05 p.m.
I am a trollish douchbag.
[Comment edited for space and to clarify intent. Go troll somewhere else. --Ed]
Carl T.
March 4th, 2007
10:17 p.m.
I remember seeing a post by Guido about some of the modules that weren't in the standard library, but I don't have the link handy.
Part of his point, if I understood him correctly, about modules like BeautifulSoup and others is that they don't have names that indicate what they do, or that the names are just plain goofy. I may have misinterpreted what he said, but he did perceive the names as a problem.
It's a small point, but if that's part of what's keeping BeutifulSoup out of the standard library, it seems like a bit of a shame.
My (weakly informed) 2 cents.
CBT
PixieDust
March 4th, 2007
10:31 p.m.
[Response to troll removed. If you don't feed them they'll go away. --Ed]
As for Python warts, I used to hate some things but by now I forgot what they were, too busy writing python programs.
Oh yeah, here's one I hate that it is not faster than C.
Pixie
laurent szyster
March 5th, 2007
4:58 a.m.
5. You don't need interfaces in Python: names *are* interfaces and
that's a much better convention for an interpreter.
4. A list is a mutable collection, which is something different than
a tuple (an immutable collection) or an iterator.
3. If you need something more elaborated than asyncore but can't suffer twisted code, have a look at Allegra (yes this is a shameless plug ;-)
2. Use distutils, that's the standard.
1. If you want to add something to the Python Library, contribute it ...
Robert
March 5th, 2007
7:44 a.m.
I am not him but it is "brian d foy" all lowercase. : )
Jacob
March 5th, 2007
8:04 a.m.
@laurent: I think you kinda missed the point of this whole exercise...
@Robert: fixed, thanks.
Paul Boddie
March 5th, 2007
8:26 a.m.
Let's run with Laurent's anti-meme. ;-)
5. Abstract base classes (mixed in where appropriate) are Python's interfaces. All those statements raising NotImplementedError might seem like boilerplate, but I suppose this is another thing done conveniently with a macro (a job for EasyExtend?) - changing the language would be yet another example of overkill at work, unless one plans to make use of such declarations for other purposes (which I doubt would ever happen).
4. See point 5 - and please tell us the real point 4. ;-)
3. See http://wiki.python.org/moin/ParallelProcessing for some answers, at least.
2. I can't refute point 2: I don't use Eggs, and I don't really see what they give me that my package manager doesn't already provide. Plus I have reservations about the reinvention tendencies going on in this department.
1. Your favourite packages may be alien to many other people. However, the standard library needs to be more coherent. It's great for a number of people that ElementTree is now in there (although the complaints about the docs are interesting to hear about now), but the other bundled XML tools seem to be in free fall - that's not a great advert for the governance of the library, regardless of whether one thinks, "DOM and SAX sux!"
Rubic
March 5th, 2007
9:16 p.m.
Regarding your last item: I think many problems with the library have been errors of comission, rather than omission -- "batteries included" notwithstanding. Witness the longevity of regex, soundex, and some of the Sun audio code through the years. It's much easier to add a module to stdlib than to remove it, and weaknesses in the library tend to get reflected (often unjustly, IMO) on the language itself.
-Jeff Bauer
Jeff
March 5th, 2007
11:02 p.m.
Just thought I'd mention that Java's one good idea, interfaces, isn't even a Java idea. It's directly taken from Objective-C (helped create Java back when it was Oak), and Obj-C's protocols are better than Java's interfaces anyway. Not sure what Java's one good idea would be.
Ralph Corderoy
March 6th, 2007
7:47 a.m.
Regarding threading, I'd love to see something like Plan 9's Alef's channels as a means of communication and synchronisation between Python "threads". They're far easier to program and reason about that mutexes, semaphores, etc. Perhaps py Lib's "greenlets" would be a suitable thing to build them on, leaving OS threads for blocking actions.
http://swtch.com/~rsc/thread/
http://codespeak.net/py/dist/greenlet.html
Tim Keating
March 7th, 2007
5:01 p.m.
Jacob (I presume), you misspelled "douchebag".
TK
effbot
March 11th, 2007
1:37 p.m.
1. Slower than java.
2. Limited expressiveness. No multiline anonymous closures like in ruby. Guido stated that this it is syntactically impossible. Not nearly as DSL or macro friendly as other languages.
3. self self self self - it's as if OOP was just tacked on.
4. Redundant or meaningless symbols and keywords like the colon at the beginning of a block, and all the underscores. What is "def"? Why "elif" instead of "else if"? "lambda"?
5. The python community. RTFM jerks, rude to all newbies or new ideas. Zealots about python (Guido called them the NIMPY crowd: not in my python), and they spread absolute FUD about everything else. Shot down most proposals for python, including ones Guido has proposed himself, like optional static typing or case-insensitivity. If you don't want python to ever change, stick with python 1.5 or whatever version you are holding on to.
Die python die.
Danny
March 21st, 2007
5:04 p.m.
0. significant whitespace
(Ok, let me rephrase that - what sucks is I've never found an editor I'm comfortable with)
Concurrency is hard, as it is in most popular languages. I suspect the only real answer there is to use a language built for concurrency.
Unicode feels unnatural (it shouldn't).
What effbot said. self is really annoying. Underscores, ugly.
It's easy to start writing code in Python, it's hard to learn how to write Python code (mine is still Java with significant whitespace and unreliable interfaces).
Bill de hOra
March 21st, 2007
8:43 p.m.
"Not sure what Java's one good idea would be."
The sandbox maybe; none of that buffer p0wning crap.
Oh, all right then:
5: self
4: __
3: not knowing a function's argument types. I think that means I'm in the "would like optional type declarations" camp.
2: bytestrings (they suuuuucccckk).
1: GIL. But concurrency sucks everywhere. Java sucks a bit less as long as you make sure to use queued comms; which is a poor man's actor/message passing. Ruby is also a joke. Hence I'm off to muck about with Erlang; I figure the time spend not dealing with livelocks and scaling can be poured in porting 30 or so libraries. And omigod Erlang has *headed lists*. Closures and continuations? Pfft.
karl
March 21st, 2007
8:53 p.m.
my list of 5 things I hate in Python is:
1. Documentation
2. Documentation
3. Documentation
4. Documentation
5. Standards library which are not in the standard library :)
Documentation has really to be improved. Each feature should have a piece of code showing a possible usage of it.
Giacomo
March 22nd, 2007
10:10 a.m.
Sorry, but your point #2 really looks weak. When you compare how python handles libraries (source included in each and every lib, in a zipped archive) to any other languages, well... java has these compiled funny things called .class, hidden in never-ending directory structures inside a zip file; DLLs are as transparent as mud; and I bet that you won't do much of a "view source" with C libraries :)
I'd say python eggs manage to integrate the best of two worlds (using compression and maintaining full source). How would you change it?
The problem with import I/O is real but it's a different matter, and it's shared by pretty much any comparable environment. Again, there is no easy answer.
Jeremy Bowers
March 29th, 2007
11:54 a.m.
While PyPy has a lot of cool stuff in it, the one thing that gives me hope for the long-term survival of Python is that the Stackless stuff has been a first-class priority from day one, with the original author heavily involved. Combined with implementing Erlang ideas with manual discipline (communicate across greenlet boundaries only with immutables, or one-time initializations with mutable objects that the source process then forgets about entirely), and the fact that I *think* PyPy has no GIL, and you've got an Erlang-esque environment without the (current) pain of doing anything in Erlang.
I hope PyPy matures to the point where it can replace the C-based Python within the next couple of years.
Some Dude
March 29th, 2007
12:31 p.m.
@karl
I couldn't agree more with your points 1 and 2, Python really needs to have a much richer collection of documentation, but you are crazy for thinking 3 and 4 are problems, there is not a single thing to improve about Python documentation.
Martijn Faassen
March 29th, 2007
12:38 p.m.
As one of the authors of lxml: One reason why it's hard to include lxml in the standard library is that it depends on libxml2 and libxslt. These would then become dependencies of Python, which may be too heavy of a burden.
Another reason why lxml would have a hard time making it into the standard library is that it depends on Pyrex (and actually a slightly patched version of Pyrex). Pyrex is not well known to lots of developers so may introduce a maintenance burden the standard library maintainers do not want to take on.
Luckily lxml is available on the cheeseshop.
Note that many issues with eggs can be compensated for by using zc.buildout. It has a learning curve, but allows you to control which eggs are on your path very carefully, as it doesn't install eggs globally. It certainly made my life immensely easier.
Joe
March 29th, 2007
4 p.m.
Could you enlighten an outsider? What the heck is the point of an interface in a dynamic language? I always thought the point of an interface was to keep your static typechecker happy. As long as the object implements the methods you need, isn't it all good?
Maybe it puts a little more burden on the documentation, but if you want your language to provide type documentation for you, there are plenty of statically-typed languages in the world. Why add a language feature that has no functional effect whatsoever?
Of course I've been messing with smalltalk lately and maybe that warps my perspective, but I just don't get it.
Armin Ronacher
March 29th, 2007
4:28 p.m.
1.) Yes. Eggs suck. However you can acccess the source of an egg using __loader__.get_source. Also have a look at http://code.djangoproject.com/ticket/3734
2.) Interfaces. Yes. They would be a good thing. But with the new metaclass system of Python3 those could be added right to the core. (using class Foo(implements=[IFoo, IBar]))
3.) concurrency: GIL sucks. Hopefully PyPy will fix that once it's usable.
Regards,
Armin
Phillip J. Eby
March 29th, 2007
9:55 p.m.
In Python 2.5, pydoc and pdb work correctly with eggs (and other zipfiles).
Also, your information about sys.path is incorrect. If you install zipped eggs, there is no extra stat'ing that takes place; Python since 2.3 caches zipfile directories in the zipimport module, so no system calls are needed to check the importability of something from a zipped sys.path entry, once the initial read of the zipfile is done (which happens the first time an import tries to look at the zipfile.
Finally, if you want source, use e.g.:
easy_install -eb. FooBar
and you'll get a nice './foobar' directory with the package's original (pre-egg) source. (The -e is short for --editable.)
Kevin Watters
March 29th, 2007
11:06 p.m.
As of Python 2.5 you can send to generators, so they are really coroutines in disguise.
"Views" or interfaces or something of those sorts are coming in Python 3000, and I believe standard library reorganization is a priority as well.
Kevin Teague
March 30th, 2007
3:17 a.m.
I've only used zope.interface in Python, but I quite like it. zope.interface declarations make excellent reference material when you are trying to use software that someone else wrote.
I don't think "feels clunky" is a valid critique of zope.interface. Alhtough I might apply the "feels clunky" critique to zope.interfaces use of camelCase methods as opposed to under_score methods.
@joe
Interfaces in a dynamic language can be thought of as a formal way of describing what methods an object is supposed to implement. The statement "As long as the object implements the methods you need, isn't it all good?" only holds true if you know *what* to implement.
In addition, if you want to perform an action based on the type of an object, interfaces can make that kind of code much more concise. For example, if you want to do one thing if your object only implements getFoo and getBar, but another thing if it additionally implements setFoo and setBar, you could end up writing a fairly lengthy set of conditional statements. With interfaces you could write something like:
if IFooReader.providedBy(object) and IFooWriter.providedBy(object):
# do stuff
elif IFooReader.providedBy(object):
# do other stuff
else:
# raise an error
Paul Boddie
March 30th, 2007
7:43 a.m.
Hmmm. Is that effbot being sarcastic or is it really Doug Holton?
Pixie
March 30th, 2007
8:13 a.m.
> Hmmm. Is that effbot being sarcastic or is it really Doug Holton?
It's Doug, who else.
Booooo.
SirMo
March 30th, 2007
9:42 a.m.
I don't mind self. due to the fact that it makes the code much more readable as opposed to Java where you have the option of omitting this. I mean you're typing way less code as opposed to Java anyways it's an ok compromise for more readability.
I agree about the naming convention for the eggs though.
Phillip J. Eby
March 30th, 2007
12:04 p.m.
"""With interfaces you could write something like: [snip]"""
Please, don't. Interface introspection creates code that is closed to extension. Have you ever tried creating objects that work correctly when pydoc tries to document them, for example? [shudder] Interfaces without adaptation are an accident waiting to happen, and pydoc is a good example of why if-thens based on interfaces are evil.
See these three posts for a full explanation, including why interfaces end up being helpful in Java in a way that they won't in Python (and no, it's not about multiple inheritance):
http://mail.python.org/pipermail/python-3000/2007-March/006206.html
http://mail.python.org/pipermail/python-3000/2007-March/006232.html
http://mail.python.org/pipermail/python-3000/2007-March/006244.html
keep it simple
April 27th, 2007
8:18 a.m.
Just a beginner (in python, not in programming) so I won`t comment 5-2. But not everybody does webstuff with python, there is no need to include every web library into the standard. Even the other two are specialized. Standard doesn`t mean include everything remotely useful to somebody. Simple and extendable is better, than big and unwieldy.
Tom Barta
May 2nd, 2007
1:49 p.m.
My thoughts:
- Explicit interfaces impose undue inflexibility in the language. Maybe what you are looking for is more along the lines of published standards (e.g. DB-API 2 or WSGI). If you are looking for executable documentation, there's no functional difference between interfaces and ABCs (though since Python supports multiple inheritence it seems silly to not use it for ABCs).
- I much prefer having a CPAN-esque approach to including modules. Python the language and standard library can move slowly, whereas specific packages such as PIL, SciPy, or SOAPpy can move at their own pace. I'm actually typically surprised whenever I discover new modules installed by default (makes me wonder what else is installed under my nose).
- I agree with concurrency being a problem, with the GIL. I've had my share of Twisted programming and I absolutely hate it.
Adding things that I don't like about the language myself:
- __ for private
- no obvious way to declare member variables. I just define them all in my constructor, but I like being able to see the structural definition of an object without having to examine the behavior.
- unicode is difficult to "get right" for a beginner, and relevant documentation is rather lacking
- os.exit() doesn't do what you'd expect in anything but the main thread (it raises SystemExit, which only kills the program if raised in the main thread)
macdet
May 14th, 2007
2:36 p.m.
me and my wiki are happy in still in love :)
http://mobbing-gegner.de
Give python, moinmoin and django an chance to survive!