
Why Python is Important for You - zzzeek
http://blaag.haard.se/Why-Python-is-important-for-you/
======
ak217
I like to call this cognitive compatibility - the amount of effort required
from an uninitiated English-speaking observer to understand what a program
does. Most people who are deeply familiar with a language will have a tendency
to discount this effort, but really it is essential because it minimizes the
translation layer that your brain has to use any time you read code.

Python encourages code which is readable in English and reasonably brief.
Having readability, consistency, and the "principle of least surprise" as
primary language and community principles ultimately saves developers time and
makes them more efficient.

And the maturing of PyPy is incredibly exciting.

~~~
andolanra
I want to make what I think is an important qualification which conflicts with
a reading of your comment: Python is readable to people who are familiar with
conventional Algol-based programming, i.e. every modern programmer. That does
_not_ make it readable to an arbitrary English-speaker, which is an assertion
I sometimes hear: "Oh, Python is so much like English, people who aren't even
programmers can read some of it!" Which I can say from experience is not the
case in the slightest. If it were, my job—which involves teaching Python to
non-programmers—would be inestimably easier.

Python is simple and easy because it takes everything you know from other
languages and systems and makes those things simple and easy and pleasant to
do. I've even seen Python used as a kind of runnable pseudocode for projects
that would eventually be written in other object-oriented Algol-based
imperative languages, which is a testament to how well it distills those
concepts down and makes programming simple. But it is not "readable in
English." It is readable in pseudo-Algol.

~~~
tsunamifury
Thankyou! So many programmers seem to forget they have an enormous base of
syntax and logic which is not at all like natural language. They see python
and say, oh wow this is so easy to read, just like English! But its only an
easier way to express a syntax that really is nothing like what a
nonprogrammer would consider English.

~~~
shazow
It varies.

When I was helping @limedaring learn Python, I'd read source with her and
explain what it does. Quite often I'd feel somewhat embarrassed when
explaining what a line does by verbatim reading what it says.

"for user in users: ..."

"if user.is_admin: ..."

It was especially nice that the topic of "what code block does this condition
apply to?" did not even occur to either of us. The indentation-based blocks
made it completely organic. (Try explaining Bash to someone and when to use
do/done, if/else/fi, case/esac.)

But sure, things get weird with decorators and generators and other advanced
features.

~~~
loxs
IMHO, decorators, although very useful are a _big_ departure away from
python's "simplicity" in syntax. I remember having lots of headaches several
years ago wile trying to fit it in my brain. Even after I realized it is
something as simple as JavaScript's myfun(fun(){}), my brain somehow continued
denying to absorb it.

~~~
dcosson
Agreed that they can be tricky initially and hard to debug, but I think
they're totally worth it for eliminating repetitive code. And IMO as long as
there isn't a bug in the decorator itself, code with decorators can be just as
readable (if not more so) to someone else (e.g. decorating your functions with
@authenticated instead of if self.user.is_authenticated: # blah, blah blah)

~~~
craigyk
if Python had better function syntax and anonynous functions, decorators
wouldn't even be a 'thing'

~~~
irahul
> if Python had better function syntax and anonynous functions, decorators
> wouldn't even be a 'thing'

Better function syntax? What's wrong with python's function syntax and how
does it relate to decorators?

Python does have anonymous functions, though they are limited: You can have
only 1 expression, you can't have statements, and you can't have local
variables. The reasoning is lambdas should be used for small operations; for
everything else, named functions should be used.

The reasoning behind lambdas is arguable, but it still doesn't explain how it
affects decorators.

Consider:

    
    
        def memoize(fn):
            from functools import wraps
            @wraps(fn)
            def memoized_fn(*args):
                if not memoized_fn.cache.has_key(args):
                    memoized_fn.cache[args] = fn(*args)
                return memoized_fn.cache[args]
            memoized_fn.cache = {}
            return memoized_fn
    
        @memoize
        def fib(n):
            if n < 2: return n
            return fib(n-1) + fib(n-2)
    
        print fib(100)
    
    

What would a _better function syntax_ and _anonymous functions_ do so that
_memoize decorator won't be a thing_?

~~~
maxerickson
Less restricted anonymous functions would allow stuff like this:

    
    
        fib=memoize(function...)
    

So the @ shortcut for:

    
    
        def fib():
            ...
        fib=memoize(fib)
    

wouldn't be necessary to 'clean up' the decoration of the function.

~~~
irahul
Even if it were possible, I would stick with

    
    
        @memoize
        def fib:
            pass
    

_fib = memoize(function ...)_ has unnecessary nesting, and _@memoize_ is
cleaner IMO.

I am curious - do you find _@memoize_ confusing? Personally for me and anyone
I have talked to, _@memoize_ is vanilla - the confusing part is the decorator
itself, especially one that takes arguments; that coupled with the fact that
classes(which override __call__) and functions are both used as decorators.

~~~
maxerickson
No, I don't find it confusing. But I read craigyk as mostly talking about the
special decorator syntax, not function decoration in general.

------
pranjalv123
My biggest problem with Python is that projects larger than a given size tend
to become unmaintainable rather quickly.

This is in large part because of the lack of strong typing and type
annotations; if you aren't the only author or can't keep the codebase in your
head, it takes real effort to figure out what a function does. Even the type
annotations provided in a language like Java or C++ make this task much
easier, not to mention languages with real strong type systems like Haskell.

That's not to say that building large systems in Python is impossible, but it
takes a lot more effort and documentation that it would in other languages.

~~~
evincarofautumn
This is a significant problem for me as well, coming from C++ and Haskell.
Even just going through and making a few changes here and there, there’s _no
way_ for me to know without extensive testing whether my edit was even
remotely correct beyond a cursory syntax check.

I’ve never had to deal with testing all that heavily in statically typed
languages, because I can rely on the type system to do a lot of very helpful
static analysis. The lack of basic static knowledge about a Python program is
frustrating and discomfiting, and ultimately discourages me from using the
language for anything serious.

~~~
cdavid
I find the focus on dynamic typing a bit fascinating: you don't see people
focus so much on it on a discussion about LISP. [EDIT: I meant to say that
this most likely reveals something else is at work in the particular case of
python].

When a C program compiles, it really does not tell you much about whether it
will work or not. Maybe it is a matter of application domains, but I tend to
actually spend more time testing C parts of the code compared to the python
code. But, in proportion, I spend more time testing in python than in C,
because I spend so much less time doing things in python than in C.

Haskell is different, because types can be used to enforced constraints in a
much better fashion than C/C++/Java/etc…

The one part when simple typing systems is useful is refactoring. Doing so in
a dynamically typed language is difficult (but possible, as shown by
smalltalk, which is supposedly even more dynamic than python).

~~~
evincarofautumn
Lisp’s other useful features just make the particulars of the type system less
of an issue. When writing prototypes, I move things around and refactor a lot.
Python makes this easy at the cost of certainty about whether it was done
right. I don’t write a lot of Lisp, but in my experience refactoring there is
quite different: I’m not editing methods and classes, I’m factoring functions
and macros. If I were one for supposing, I’d suppose the OO philosophy of
Python forces you to create interfaces before you necessarily know that
they’re correct, so you end up refactoring them, and there’s poor support for
that when no static type system has your back.

~~~
cdavid
This is already a more interesting discusion. I cannot comment on Lisp, as I
have too little experience with it. When you say python forces you to create
interfaces, I am not sure I understand. For me, programming is mostly about
creating interfaces (as the interface part of API), python or not. When I
refactor some C code, static typing does not help me that much, as what's
difficult in C is lifetime's object (e.g. ref counting in C extensions),
things like that.

What is true is that it is easy to write code that is impossible to refactor,
because it is full of globals, or "stringified API" (e.g. using a dict instead
of objects when the set of keys is supposed to be fixed). But I am afraid
people writing this kind of code would write bad code in any language, or are
at least very inexperienced in the language.

------
keypusher
I do love Python, but I often wish there was more rigor for some things. I
currently work on a large project (>500K LOC) and have started to see it fall
apart with a bigger team. Lack of enforced typing in function arguments,
inability to create strict interfaces, inconsistency in standard library
conventions, and package management would probably be my biggest gripes.

~~~
cdavid
On most projects I have seen where python was seen as problematic, I think
that having types ala C++/Java would not have improved much. The real problem
is that the function is not documented, nor is the function expectations.
Typing in C++/java does not replace that (more advanced typing systems do much
better, though).

Package management and generally deployment is certainly a pain in python. I
think it is one of the main issue in typical "corporate environments"

~~~
nostrademons
In most C++/Java code, the function is not documented either. The nice thing
about manifest types is that the source code becomes the documentation (shitty
documentation, yes, but usually good enough that you can figure out how to use
it by looking at the source). Type inference with a doc generator would work
too, as long as you run the doc generator regularly and everybody knows where
to find the docs.

History has shown that programmers are too lazy/busy to write good
documentation, and when they do, they don't keep it in sync with what the code
does. If it's not checked by the compiler or automated tests, it's probably
wrong.

~~~
cdavid
It is not my experience that you can figure out how to call functions
_correctly_ just from the function signature. Certainly, that's not true from
C++ when you need to figure out lifetime issues, etc… It may be possible to
figure out from the source code, if the code is written well enough, but
that's true independently of the language IMO. Developer not writing decent
doc is an institutional problem, and if this cannot be enforced, then the
institution is most likely not capable of producing very good code either.

I think it is more interesting to talk from the POV of how to write code that
is actually readable: type may help, but that's only a not that important part
of the equation in my experience.

~~~
nostrademons
C++ with good coding conventions can encode pretty much all the information
you need in the type. If a parameter is read-only, pass by const reference. If
it's writable but ownership is not transferred, pass by pointer. If ownership
is transferred, pass by unique_ptr. If it's owned within an object or function
lifetime, use a scoped_ptr. If it can't be copied, inherit from
boost::noncopyable.

------
agentgt
I have used Python for a rather long time (I think 1997 when I was 17 was when
I first used it). As the the writer of the article stated Python is awesome
for writing "tools" and throughout my career I have used it for such.

However I have used Python also for big projects and that is where its gets a
little messy. I know I am going to get down-voted to kingdom come but I think
Java is a better language for big projects mostly because of the static typing
(try renaming a class in Python compared to Java).

Modern Java is for sure more verbose than Python and more complicated but the
languages are extremely similar (Guido has even take some of the design
consistency from Java for Python 3.0).

The reason I bring it up is Java is very often in various circles crapped on
to no end. The reality its basically just more verbose Python. Not to mention
Java offers an introduction to Parametric/algebraic typing (generics) and more
sophisticated concurrency (futures ... yes actors are better but python really
has neither).

~~~
Peaker
Just replace Java with Haskell, and you've got yourself a nicer Python
replacement.

Less code than either Java or Python, far more compile-time guarantees than
either, and nearly as fast as Java when speed matters (speed takes a bit more
effort in Haskell than in Java, but compared to Python, it is a no-brainer).

------
wging
As a commenter on the article wrote: what about Ruby?

I say this as a happy Python user. Ruby seems very similar but I'm reminded of
a pg essay on language power: looking _up_ the power curve, you see '$Language
plus a bit of weird stuff that is probably irrelevant.' So I don't trust
myself.

As someone who loves Python and doesn't know any Ruby beyond a few bits of
syntax and the obvious bits that are common to most languages, what am I
missing?

~~~
wcarss
Ruby's blocks and built in regular-expressions are two examples of things
you're missing.

if result =~ /regex/

that kind of thing is awesome for readability, but it can also be pretty darn
slow.

There's also some interesting things about the ruby object model and
interpreter that are different from python's approach. Whereas in the python
REPL you type help(object) to get the docs on that object, in ruby you type
object.methods or object.public_methods, etc. It's less documentation
oriented, and more code-exploration oriented, but the two end up delivering
the same sort of information.

Hope that's helpful! Ruby's a lot of fun to tool around with, and there are
(in my opinion) fewer things about it to trip you up completely than there are
when first learning python. But once you use it for a while and get beyond the
basics, it becomes clear that there's a lot of unfocused cruft foating about,
which fits no rhyme nor reason. Much more than Python has.

(cautionary note: I'm not an expert with either language)

~~~
zem
ruby does have its share of cruft, but it also has some inspired features that
make a far bigger difference than you'd think they would. blocks are the
biggest (specifically, syntactic support for attaching a lexical closure to
every method call, which the object can choose to use or not), but here's
another cute one: the case statement

    
    
        case object   
          when matcher1; ...   
          when matcher2; ...   
        end
    

performs a method call on the _matchers_ , with the object as an argument,
rather than vice versa. so you can say things like

    
    
        case name
          when "John Smith"; puts "hello again"
          when / Smith$/; puts "are you related to john?"
        end
    

the string "John Smith" and the regexp / Smith$/ will each call a different
matcher to see if they match your name - a far cleaner design than the string
class having to provide matchers for everything you might want to use in a
case statement.

------
tete
I am kinda afraid of getting down voted, but I have used Python and I feel
like I get all this and more (CPAN) when using Perl. The major difference in
my opinion is that Perl gives you even more freedoms, which causes you to need
some self discipline, but you get stuff done even quicker that way.

It feels a bit like Python is better for programming beginners or people that
tend to be too lazy sometimes and Perl is for people who want to be able to be
lazier since they know what they are doing.

Also, I think Python (and most other language projects) should clone CPAN
(including CPAN testers). Seriously it's a major deficit.

I also think Python is the easiest to grasp for people coming from static
languages. Perl and Ruby are way harder.

~~~
aangjie
Ok, just as a disclaimer: i recently read Larry Wall's post on perl design
principles +natural language and am reconsidering perl.. But honestly all my
previous experience poking around with perl have been horrible... it's pretty
messed up syntax to read... i guess it may not be so hard for a perl expert..

~~~
chromatic
Most Perl tutorials do a terrible job of explaining the two or three things
you really need to understand to learn Perl syntax. I wrote Modern Perl to
rectify that:

<http://onyxneon.com/books/modern_perl/>

------
espeed
Python doesn't have the glyph noise that brace-based languages do, and well-
written Python is beautiful and easy to read.

But lately I have been having an internal debate on whether using autodoc and
inline docstrings detracts from its beauty and makes it harder to read because
it reduces the amount of code you can see on the screen (see Steve Yegge's
rant on this [http://steve-yegge.blogspot.com/2008/02/portrait-
of-n00b.htm...](http://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html)
from a few years back).

If you use Sphinx to document a method's description, params, param types, and
return type, then it can easily turn a three-line method into a 12 line
method, and then you can only see ~5 methods on the screen at a time.

So if the code is already readable, would it not be better to put the
docstring comments in an external file to keep the code density?

Django does this, and I'm starting to think it's the right balance.

~~~
mekoka
Docstrings should already be easy to detect by editors, so it would be trivial
to add a show/hide functionality. Incidentally, one could also use Sphinx to
create a plugin for that.

~~~
espeed
But not all editors have this, nor is it widely used in editors like Emacs.

And GitHub doesn't have it so it can make it harder to get a big-picture view
and see the structure of a module when evaluating different libraries online.

------
jtchang
I work with python daily. I find that when I first started I avoid a lot of
the "fancy" constructs such as list comprehensions, dynamic arguments, and
decorators as well as meta programming.

The great thing is the bar to being effective in the language is so low. You
can pretty much pick up most python code and just read it and get a general
feel for what it does. Not only that but it is much easier to read because of
whitespace delimiting.

I can generally tell the quality of a python program but how nicely indented
it is. If there are lots of indents like 5 or 6 levels deep I know something
is wrong. For a newbie if your code is hard to understand and it is in Python
you are writing it wrong.

~~~
Luyt
I find a great way to avoid deep nesting is to move code to functions, and
bail out when some conditions are not met.

As an example, this deeply nested code:

    
    
        def frob(someargs):
            if something > 2:
                ... # do some processing
                if that == "CONNECT":
                    ... # some more processing
                    if verdict in blessedsolutions:
                        ... # even more processing
                        print "Happy birthday!"
    

I tend to write like this:

    
    
        def frob(someargs):
            if something <= 2: return # Not our concern.
            ... # do some processing
            if that != "CONNECT": return # Not handled here.
            ... # some more processing
            if verdict not in blessedsolutions: return
            ... # even more processing
            print "Happy birthday!"
    
    

I do the same thing in loops, using 'continue'. The above second example looks
rather flat, but in practice the 'do some processing' statements often need
identations due to conditions and loops.

I added the processing to demonstrate that it's not always possible to combine
conditions. And, of course this way of 'bailing out early' vs. 'nested ifs and
processing' is not Python specific. The dogma that a function should have only
one exit point (as proposed by 'structured programming' adepts and Pascal
afficionados) often leads to deeply nested control structures and convoluted
testing. Brian Kernighan has written a paper on this[1].

[1] [http://www.cs.virginia.edu/~cs655/readings/bwk-on-
pascal.htm...](http://www.cs.virginia.edu/~cs655/readings/bwk-on-pascal.html)

~~~
rmcclellan
Neither solution is great. Excessive use of return and continue is an
incredibly fast way of making code completely incomprehensible.

Such complicated control flows should be treated as a major, fundamental
problem. Keeping them in place will cause bugs and prevent future contributors
from having confidence that their changes are correct. The problem of
complicated control flow is too deep to be solved with a band-aid like this,
although perhaps syntactically it looks a bit nicer. In fact, this is exactly
what people did before the so-called "structured programming adepts" came
around, except using gotos instead of continues. It didn't work so well back
then, and it doesn't work so well now.

~~~
Luyt
Hmmm, you have a point there, but what is your proposal to solve it in a
correct way, then?

Some problems need a deeply nested control flow and arcane business rules, you
have to implement that somehow, and in such a case the method I use looks like
the lesser of two evils. I'd rather have some flat ecosystem of meaningful
functions than one monolithic deeply nested control structure.

From time to time I like defensive programming, and when I write a function
'frob' that promises to frob something, that function first makes sure that
the thing can indeed be 'frobbed', and if not, bails out. This also works well
for programs that should be idempotent (although that is a whole other issue).

~~~
anthonyb
The way I would do it is to push the processing out to functions, too.
Something like:

    
    
      verdict = get_verdict(the_thing)
      if verdict not in blessedsolutions:
          return
    

I'd advise against running returns onto the same line - I find it makes it
harder to read, particularly when you have a lot of checks like this.

~~~
Luyt
_"The way I would do it is to push the processing out to functions, too."_

This is indeed a good idea to isolate code away, but wouldn't alleviate a
deeply nested control structure. It _would_ make it somewhat more easier to
look at, though.

 _"I'd advise against running returns onto the same line "_

I usually follow PEP8 and place returns and continues on the next line, but
the code examples I posted earlier had to be a bit condensed to conserve
screen space, that's why ;-)

~~~
anthonyb
Sometimes your problem space is really just that complex, in which case
there's not much you can do, short of writing some sort of business rules
engine.

------
yason
It's important because it reminds me I should keep looking.

I should keep looking instead of turning it into my Blub. I love Python but
its boundaries have been hitting me frequently for years. There probably never
will be a total sweet spot between functionality, syntax, compatibility,
support, and platform-crossing but I know I have to keep looking for a
language that's more sophisticated yet more practical.

------
kevinburke
When I was at Google there was a paper titled "Please don't use Python for
large programs." Can someone post that? It would be an interesting
counterpoint.

~~~
olalonde
What language do they recommend for large programs?

~~~
sunqiang
don't know for sure, it might be C++, Java, and now they have Go.

------
khyryk
I like Python the language, but the standard library can often annoy me as
there is no unified style. thereAreMethodsLikeThis
or_there_are_methods_like_this orevenworsefullylowercase. Gah.

~~~
ndefinite
PEP 8 covers this: <http://www.python.org/dev/peps/pep-0008/>

------
sdfjkl
Many years ago I've decided it was time to pick up a modern programming
language. In the past I had written lots of (Turbo) Pascal code, some x86 (and
more exotic) Assembler and a bit of C, but then for several years I only did
shell/awk scripts and ported C software to IRIX and SINIX/RU.

So I sat down and decided to find a nice general-purpose language that I would
focus on learning. I wasn't quite sure what for yet, but I decided I was going
to pick one and stick with it. I didn't have the time to learn multiple
languages and I didn't have a lot of time to try out different ones, so I just
looked around a little bit. Some I ruled out early: C and it's relatives were
just too verbose, I didn't want to spend the time writing all the error
handling necessary just to read a damn file. I was doing a lot of sysadmin
type work at the time and had therefore developed an intense disliking for
Java. This was based on too much badly packaged Java software that even if you
got it running at all was sluggish, hogging way too much memory and crashed
with arcane error messages. I did like the quick & dirty way I could make
things work in a shell script, so I looked mostly at scripting languages.

I looked at Perl, which was the standard scripting language at the time and
had a huge library (CPAN) of modules, which was great. I hated the syntax
though and found the code often unreadable and there being too many ways of
doing the same thing.

I looked at Pike, which had the benefit of using a C syntax (which I already
knew, so that was a plus), but it seemed not widely supported and nobody was
using it (this hasn't changed since, it seems).

I don't remember what else I looked at, but then there was Python. The syntax
was a revelation. Here someone had finally made the most of creating a
language from scratch and spent the time thinking about syntax and how to do
away with largely pointless stuff (brackets), replacing it with things that
everyone did anyways (indentation). It also came with a sizeable library of
stuff that did almost everything I could dream of at the time. It was love at
first sight.

Recently I've spent £35 on a stainless steel mill that grinds salt when you
twist it one way and pepper when you twist it the other way, just because I
really love well thought out and engineered things that make stuff that's been
around forever just a little bit better. That's how I feel about Python. It's
not doing anything fantastically new or unique, but it's doing the stuff that
others do just a little bit better.

Today I'm doing lots of web stuff, some sysadmin stuff and random hacking of
various things on the side. I'm still doing almost everything in Python and
whenever Javascript bitches at me about a missed semicolon I do think: "All
these fantastic things you can do in a web browser these days and you couldn't
figure out that this command in an entirely different line isn't part of the
previous line?".

The only thing that I can't do in Python is write software for my iPhone,
which bugs me a bit. But every time I try to get into Objective C I just get
annoyed by the syntax and amount of cruft I have to write to do anything.

~~~
mekoka
_I'm still doing almost everything in Python and whenever Javascript bitches
at me about a missed semicolon I do think: "All these fantastic things you can
do in a web browser these days and you couldn't figure out that this command
in an entirely different line isn't part of the previous line?"._

I hear you about Python, but JavaScript doesn't require semicolons either, as
far as I know. The main reason it's advisable to put them is to avoid
ambiguity when 2 statements find themselves on the same line, for example, in
a minified js file. Python uses semicolons for the same reasons, but minifying
Python files is quite uncommon (and would probably serve no real purpose).

~~~
tcard
JS semicolons are actually encouraged —omitting them, while syntactically
valid, can lead to obscure bugs. [http://bonsaiden.github.com/JavaScript-
Garden/#core.semicolo...](http://bonsaiden.github.com/JavaScript-
Garden/#core.semicolon)

~~~
ludwigvan
If you are following Crockford (JavaScript, the Good Parts), it is encouraged.
However, some, like the current node.js maintainer think otherwise; see
[http://blog.izs.me/post/2353458699/an-open-letter-to-
javascr...](http://blog.izs.me/post/2353458699/an-open-letter-to-javascript-
leaders-regarding)

Personally, I still follow Crockford's advice though.

~~~
wyuenho
And you guys just demonstrated yet another reason why I choose Python for my
go-to scripting language. Semicolons are completely redundant in Python and
the language is so clean and the style guide PEP 8 is so natural, you rarely
hear about these meaningless formatting style bickering in other languages.
Saves so much time from arguing.

------
Peaker
"Weirder languages (e.g: Haskell)" sounds like something a Blub programmer
would say.

How is Haskell "weird"?

I've used Python for many years, but only recently have I migrated my last
Python niche (simple scripts) from Python to Haskell. I've found that even
there, Haskell has become more productive.

~~~
masklinn
> How is Haskell "weird"?

Functional the world (of wide-spread computing languages) is imperative, lazy
the world is eager, objects-less when the world is object-oriented, curried
when the world is uncurried, pattern-matched when the world is conditional and
brings up "strange" concepts from mathematical bowels like "monads",
"functors" or "zippers" when the world barely iterates on arrays.

How is Haskell _not_ weird from the point of view of 99% of the developers
population? Knowing, liking or using Haskell is not even relevant there,
Haskell _is_ weird because it _is_ an alien to the majority in the same way
Smalltalk, Erlang or Clojure are weird (but for different reasons, for the
most part).

~~~
Peaker
I understand "different". Not "weird".

~~~
masklinn
They reify to the same thing, something different looks weird, and something
weird is different.

------
danbmil99
Python is great in every way except one -- it isn't Javascript.

(to clarify: I'm not saying JS is a superior language. I'm just saying it's
going to win out in the end because of the history of its implementation.
There is a serious benefit to having one language everywhere, and JS is the
only viable candidate because of the investment in client-side sandboxing and
performance -- two features which turn out to matter almost as much on the
server as well.)

~~~
alextgordon
I wasn't aware that Python and JavaScript were in competition. Or for that
matter, that JS is by any stretch of the imagination "invested in
performance".

People don't use Python because of its merits as a programming language. They
use it because of the excellent standard library, Scipy, Sage, etc. While it
may be that in a decade JavaScript has built an ecosystem to match, I frankly
don't see why anybody would bother. We already have Python, why would we
invest such effort into a less suitable language?

JavaScript is tolerated by web developers, because they're forced to use it on
the client, and so there's a benefit to also using it on the server to prevent
duplication of effort. But there is absolutely no reason why non-web
developers would or will ever use it outside of that niche.

~~~
danbmil99
> non-web developers

Sorry, not sure what that means </sarcasm>

OK maybe not _everything_ will be a web app, but pretty much everything that
isn't some deep driver-level boot code or embedded firmware is already almost
always part of some sort of web app, and the stuff that isn't is pretty much
all written in C/C++.

When is the last time you wrote a Python program that didn't interact over TCP
or equivalent with some other process? And how often was that other process
_not_ something at least nominally webby?

~~~
alextgordon

        > When is the last time you wrote a Python program that
        > didn't interact over TCP or equivalent with some other
        > process?
    

My last python program was a set of scripts to help me analyze music harmony.
Entirely CLI based.

Before that? objcfix - a refactoring tool. Again, CLI based.

That's not counting the multitude of small scripts I write on a day to day
basis. I've written a large amount of Python code, and very little of it
interacts with a network.

Put it this way: Python was invented in 1991, the same time as the web. It
didn't become a _good_ tool for making websites until after 2005 when Django
arrived. So, what did people _do_ with it before then, if not make websites?

    
    
        > but pretty much everything that isn't some deep driver-
        > level boot code or embedded firmware is already almost
        > always part of some sort of web app, and the stuff that
        > isn't is pretty much all written in C/C++.
    

This is not the reality we live in. There's:

* Games (either written in C++, Objective-C or Java nowadays, plus a bit of Lua)

* Big Software: MS Office, Photoshop, Avid, Logic, InDesign, etc. Written in C++

* Scientific Computing: Written in C++, Matlab, Mathematica, Python

* Financial Computing: C, C++, Java, and a tiny spot of OCaml.

* iPhone/Android Apps: again, Objective-C or Java.

* "Enterprise Software", whatever _that_ is. Java.

And as you point out, embedded software. Everything around us runs Embedded C.

The future is the same as the present: full of a rich and diverse selection of
languages.

------
user0398
Mostly true 'cept for pythons built in pasta makers:

<http://www.python.org/dev/peps/pep-0318/>

~~~
Luyt
Yeah, that's fun ;-) I wish there was a

    
    
        if main:
            ... # do some processing
    

instead of having to write:

    
    
        if __name__ == "__main__":
            ... # do some processing
    

That'd make DHH happy, too ;-)

~~~
anthonyb
I find that the best way to fix this is to write your program as a library,
then the part that you're supposed to run as a script which imports and runs
it. No __underscore__magic__ required.

------
aDemoUzer
I could not agree more. After learning the python idioms, I realized how much
time I have wasted doing similar things in PHP. Python has gotten lot of
things right. I don't feel cramped by a language as I have with Java.

Python idioms :
[http://python.net/~goodger/projects/pycon/2007/idiomatic/han...](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html)

------
DodgyEggplant
True. The real magic: The basic constructs are so simple, so how the output is
so robust? And picking old or library code is always easy!

------
a_a_r_o_n
Executable whiteboard.

------
pnathan
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.

~~~
tikhonj
You forgot _mutable_ default arguments!

    
    
        def fn(ls=[]):
          ls += [1]
          return len(ls)
    

(My syntax might be a little off, but you get the idea.)

This will return an ever-increasing number if called repeatedly with no
arguments.

Also, the reliance on tuples, particularly tuples of _one_ item always gets me
because (1) and (1,) are different.

Also, the scoping for list comprehensions doesn't make sense:

    
    
        x = 11
        [x for x in [1,2,3]]
        print x # 3!
    

This has also gotten me in the past.

~~~
llimllib
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

------
keypusher
See also: <http://xkcd.com/353/>

------
igorgue
Haskell is not weird.

