Python Sucks, Like Everything Else
I think Python is the best language that I can use, today. I am (or was) primarily a C programmer. I think C was a lovely language back in the day, and that it’s still a very powerful if not practical language today. I think C++ is useless. I think Java is worse than useless.
Python is far, far more pleasant to work with than C, Java, Perl, or even PHP. Ruby, I’m still debating on. As of now, I consider myself proficient in C, PHP, Web languages like HTML and CSS, and Python. I consider myself to “know” but not actively work with C++, Java, Ruby, Perl, sh, and maybe some others. I prefer Python to any of these languages.
However, this page is not about why I love Python, but why I also hate Python. When I say “hate” I really mean “find inconvenient.” None of these would stop me from using the language. These are just things I’d like to see fixed/otherwise dealt with.
I discovered these things as I worked with Python in late 2004. I’ll try to keep this page up-to-date; however, some of these items may have been fixed or had solutions that I wasn’t aware of (even though I did Google most of these to see if there were any reasonable popular solutions). Bear with me.
There’s no way to do a catch-all except clause with an extended info.
That is, you can do this in Ruby:
rescue => errstr
puts errstr
exit
end
And that’ll catch all exceptions (well, all SystemErrors) and give you the
info in errstr. Come to think of it, you might be able to do:
except Exception, e:
print e.strerror
sys.exit()
In Python, but, that wouldn’t work in all cases, since not all exceptions
are derived from Exception (this is the case in Ruby as well, though). Also,
different exceptions give you different kinds of e. Some are objects, some
are strings. Another inconsistency.
Also, I’m not sure if this would work:
except (Exception1, Exception2), e:
...
And work as you’d expect. That is, for either Exception1 or Exception2,
put the extended info into e. In Ruby this would be:
rescue Exception1, Exception2 => errstr
...
end
The kludgy except syntax in Python is to blame for this.
len() is really object.__len__(), et al.
Why did they do this? I hate all of the gaping inconsistencies in Python. I think this is it’s biggest down side.
Though, I must admit, Python has the least inconsistencies of any language I’ve ever used, excepting maybe Ruby.
There’s no static.
That is to say, there’s no way to say “I want this variable to stay in scope regardless of function calls.” The one exception to this is generators, but that limits the usefulness to iterators.
PHP has static, and Perl uses globals extensively. The only way to get
around this is either have an empty class (ugly) or an empty module (uglier)
to set variables you need to stick around in.
There’s no native string interpolation support.
That is, you can’t toss variables in strings without using printf-esque
format specifiers. There’s an extension around that lets you do something
like this:
print $'a $(variable) within a string'
Update: Well, that was the original complaint, but I’ve found that I like
printf-esque format specifiers better than Ruby’s interpolation,
and find myself wishing for it in Ruby.
Update: Okay, that’s it. Just to deter the slew of idiots emailing me about this: when I say “string interpolation” I most obviously mean in terms of evaluating variables to their referenced values within a string with no extra work, as in the above. I’m very much aware of Python’s printf-esque specifiers and I use it quite often (after all, what Python programmer doesn’t? We’re left with little choice). However, there seems to be a large numbers of stupid sons of a bitches that want to debate the meaning of “string interpolation” with me. I’ve said this before, and I’ll say it again:
- I’ve heard it before, and;
- I didn’t care the first time.
I know that technically parsing the printf-esque format specifiers qualifies as “string interpolation” but you know I figured anyone with half a neuron floating around upstairs could figure out what I meant with the insane amount of context I gave. I really don’t give a shit that you’re some pedant that argues for the sake of arguing because you’re a donnish fuck that gets off on being right all the time. Yes, you’re right; now, please stay kindly out of my inbox.
I absolutely despise asyncore.compact_traceback().
I’d like to beat the pothead that was brilliant enough to think “hmm… let’s see what I can do to completely ruin a very useful language feature of Python… I know! I’ll take the verbose, useful tracebacks that Python provides for debugging and pack it all on to a single nonsensical line and expect anyone to actually appreciate it!” into the ground with a sack of hammers.
Considering most of my code is in asyncore.dispatcher classes or calls
functions from within a socket event from asyncore and that I can’t fucking
read the shit that asyncore.compact_traceback() spits out, debugging my
programs ends up being insanely hard.
I can’t seem to override this in any sane matter without involving half a
dozen method calls in traceback. Most of my programs fork() off from a
terminal so just doing a raise won’t help anyone. As of now I open a
trace.txt and have traceback.print_exc() dump it into there. This is an
acceptable but not readily apparent solution.
The interpreter is slow.
I’m serious. Perl, Ruby, and sometimes even Java outperform the Python interpreter.
Some people try to explain this with “well, Perl’s been around a lot longer and has a stronger following so all the Perl users hack up the interpreter until it’s optimized out the ass.” That may be true, but Ruby has been around for a lot less time than Python. There’s no excuse here. Python is wonderful, I just wish it were faster. There’s absolutely zero excuse for being slower than Java.
I think the interpreter is just doing too much crap and something needs to be done about it. Otherwise, Python will never be fast enough to do application-level programming with.
Where the hell is switch?
Guido (the guy that wrote Python, hereby referred to as “BDFL”) seems to
have some religious dislike for switch as there have been a few PEPs on the
issue and he seems to shoot them all down with “we don’t need switch!” Well,
no, we don’t need it. We also don’t need built-in lists, hashes, text
manipulation routines, namespaces, dynamic typing, or hell, Python itself.
We don’t need them, but they sure are nice.
Where the hell is enum?
All of the hacks to emulate it are terrible.
Of course, without switch, who needs enum?!
All string operations are mind-numbingly expensive.
Unfortunately, I see no way around this in the interpreter. By the time you went through the work of manipulating the data types in C to make strings mutable, you’d probably have so much overhead that it’d be just as expensive as slapping together a new string.
I don’t know how the interpreter deals with strings (I would think the
fastest way would to be a struct with a char * and some function pointers for
the object methods. Of course, calls to malloc() and friends are also
expensive) so I can’t really suggest anything for this.
I can’t seem to delete items of a list/dictionary that I’m iterating over without doing something insane like creating a second list of things to delete from the first!
However, there is a way to fix this in the interpreter. Use a macro to loop over the linked list or whatever the interpreter stores lists as and use an extra pointer as a temporary data storage holder. For example:
#define LIST_FOREACH_SAFE(pos, n, head) \
for (pos = (head), n = pos ? pos->next : NULL; \
pos != NULL; pos = n, n = pos ? pos->next : NULL)
Update: Well, that was my original complaint, but there seem to be several
widely-accepted ways to deal with this; the most popular being list
comprehensions or filter(). These both work well.
Another popular method is to iterate over a copy of the list (for i in li[:])
and deleting from the original. This works, at the cost of creating lots of
random garbage.
Update: It seems as if Python stores lists as arrays internally, for whatever reason. I don’t see how this is better or faster than a linked list, but what do I know. Anyway, my macro wouldn’t work on an array.
It seems as if Python tries to discourage you from using global variables at the syntax level.
Yes yes, globals are evil, they drink blood and sell pot to minors blah blah. However, sometimes they’re just plain necessary.
That being said, I can’t seem to find a sane way to say “this is a global variable, and it should be in every namespace no matter what.” The only solution to this that I can see is throwing all “global” variables into their own module and import it (I do this now, and it’s clean and I rather quite like it, but still).
I can’t seem to find an “unbuffered” mode for filelike objects.
Sure, I can call the object’s flush() method every other line, but would
something like file.setbuffered() be too much to ask?
The difference between staticmethod() and classmethod() is arbitrary and stupid.
Really.
The syntax used to designate a method as a staticmethod() or a classmethod() is mildly retarded.
The introduction of “function decorators” in 2.4 “solves” this “problem.” I’m not sure I really like function decorators either, though.
It’s hard to live without one of:
- Forward declarations, or;
- Look-ahead assertions.
I’d prefer the latter. The PHP interpreter can do this, why can’t Python?
When I say this I mean if you use a function that hasn’t been defined yet (it’s further down in the file), the Python interpreter raises a NameError saying it doesn’t exist. Of all the wonderful, advanced, high-level features that Python offers, this seems pretty basic.
Tuples suck.
Don’t get me wrong, I like the idea of them. I like them so much that I’ll go to implement something with them and half way through writing I’ll remember that they don’t have any methods! Why not? They can be immutable and still have methods, just not methods that change them. Is that so hard? I think it probably is, because tuples probably aren’t real objects, but just some collection hack in the interpreter.
Sure, you might think you can solve some problems by using a “immutable list,” but then writing any code becomes a disaster because of the mind-blowing worthlessness of tuples.
0 TrackBacks
Listed below are links to blogs that reference this entry.
TrackBack URL for this entry: http://mt.ericw.org/mt-tb.cgi/283
