Python Programming Language Advantages

by Mike Levin on January 12, 2011

This article is not about Python vs other languages, so much as it is about those peculiarities of Python that made it endearing to me—a non-professional programmer whose achievements at work came directly from being able to program. I code almost every day at my job… but not as my job.

Python Programming Language AdvantagesMy first programming experience was in 1982 on BASIC on a Radio Shack TRS-80 in summer camp, and I worked for Commodore as a student intern from ’88 through ’90. Yet, I never became a professional programmer, instead taking it up whenever in my mind the nature of my work demanded—but never explicitly as a stated part of my job. I’ve carried out sizable projects in AREXX, TCL and VBScript. At various times, I’ve attempted to take up PERL, C++, Java, ASP.NET and Ruby. Of course, I dabble in JavaScript, and intellectually, I’m drawn to LISP.

But today, it’s time to talk about Python’s strengths, and why for the first time in my life, I’ve found a computer programming language I actually love—so, this may be a good read if you’re choosing your first programming language. Most of the other languages I mentioned ended up feeling like a necessary evil in getting my job done. In all fairness, a couple years ago I thought I loved Ruby, but in hindsight, it may have just been an infatuation. Ruby just didn’t stick, and today I attribute that to its forced objected oriented-ness.

Ruby and Python have a good amount of similarity, and they’re both sometimes described as “fitting your head.” In other languages, the portion that doesn’t fit in your head is… drumroll please… overhead! The rest of this article is dedicated to the advantages of Python programming that actually got me excited about coding again.

Cutting back the overhead – Python indentation advantages

Now what do I mean by this? The clearest example is the non-use of curly braces—or brackets of any sort, for that matter—as code block delimiters. One of the most debated matters of programming style in BCPL-derivative languages such as C and Java is “indent styles”, or how to arrange those curly-brackets for maximum readability—which happens to make absolutely no difference in how your program actually runs.

Ruby, Visual Basic and most non-C derivative languages use keywords such as Ruby’s “def” and “end” for code blocks, instead of using curly-brackets. Python takes it one step further and uses a keyword only at the beginning. The rest of the code block is contained merely by virtue of line indenting.

For example, Python vs other languages…

C++ (Placement of curly brackets arbitrary and a matter of style):

void function functionname(arg)
{
    some code
}

…which can also be stated in this and other ways…

void function functionname(arg) {
    some code
}

You can’t imagine the time wasted on the discussion of the merits of each, and how ugly code gets when followers from each camp try to combine their code. Keyword languages are a little different…

Ruby (Uses keyewords instead of curly braces)

def functionname(variable)
    some code
end

This is still allows matching end confusion to occur, especially with nested functions…

def functionname(variable)
    def nestme
        more code
end
    some code
end

Python (Only one keyword, but indents matter)

def functionname():
    some code

There is only one way to state this in Python. Well, that’s not technically true. You can indent the first line as much or as little as you want, but then all subsequent code in the block must remain consistent with the first line. By convention, most people use 4 spaces for an indent (not tabs), but I use only 2. I’m a rebel. That’s about as rebellious as you can get with Python programming style.

Now this flies in the face of modern programming conventions where white-space generally doesn’t matter, and code formatting is largely a matter of personal style. But Python uses the equivalent of a school dress-code, ensuring a certain amount of conformity between members, and… drumroll please… the elimination of overhead!

Python Indents Dresscode

With enforced formatting, not only do you not need to decide how to dress in the morning with Python, but you also purge hundreds of lost man-hours resulting from indenting ambiguity. If it’s indented in Python, then it belongs to that code-block. Readability skyrockets and misunderstandings plummet (apologies to personal expression). Not only is this a personal advantage in efficiency, but it makes Python well suited for open source or other projects where programmers must collaborate on the same code.

The flip-side is that almost no other popular programming languages work this way. If you are making Python your “native language” (i.e. your first programming language—the language that you will end up “thinking in”), you are NOT getting used to the BCPL-style curly braces that are littering up so many other languages like Java, JavaScript and all variations of C, such as C#, C++ and Objective C.

Whether this is a good thing or not is a matter for philosophical debate. I made my choice, preferring to strip out the overhead in 99% of what I do day-to-day, and deal with it in those rare instances when I really have to use C to optimize my Python code (more on that later). After stints with Java, C++ and JavaScript, you can’t imagine the relief of getting curly braces out of my life.

No ambiguous ducks allowed!

Okay, so indenting matters, and that’s the single biggest personality-shaping characteristic of Python. Code gets more terse. Speaking of terse, Python doesn’t require declaring and typing variables before using. The first time they’re used, they’re declared, and they hang around until you go out of scope, and they get destroyed. This is called duck-typing with garbage collection—if it quacks like a duck, then it’s a duck.

This is the second most personality-defining part of the Python programming language from my perspective, but not just for duck typing, but for how it’s implemented to reduce misuse. It’s hotly debated whether duck typing is good for writing stable, bug-free code, but it’s awesome for making your program even shorter and even more readable. But how can a language be worthy of loving if ambiguous duck typing lets bugs in?

As a concession to keeping bugs out, Python creates a forced-stop error if you try to do anything ambiguous with a variable, like adding a string and an integer. For example, ‘Ni’+3 would fail, because Ni is a string and 3 is an integer, so you might want concatenation or type conversion. But ‘Ni’*3 will succeed, because there is no such ambiguity and this can only mean Ni 3 times.

So, Python is indeed duck-typed, but it won’t do any of that auto-conversion magic for you if there’s more than one possible meaning. That gives you all the advantages of duck typing without the one whopping huge drawback (of letting bugs in). If it’s ambiguous, it raises a fatal error—that’s a pretty big tenant of Python. The net result is that all those bugs that variable-typing Nazis get furious about just don’t happen in practice because the code immediately stops running until you fix it. Again, the net result is shorter, more readable, reliable code that also happens to be easier and faster write.

But to really appreciate this, you have to consider the time you spend typing and sizing variables in strictly static languages, like C or… gulp… Scala. In those languages, you must do it on every new variable at the time it is created. This is basically everywhere in your program—hundreds, thousands, tens-of-thousands of times throughout your program. With explicit variable typing comes tons more code to manage, whereas with Python, you must be explicit only at the moment where something might be misinterpreted when you try to use it, otherwise the program won’t run.

These instances of ambiguity are less-common, and identified for you the moment you try to run the program, so Python is actually still favoring explicitness. It just favors it at the less-common moments when it’s necessary versus explicitness all over the place (for no good reason, given Python uses an interpreter versus a compiler). Of course static languages that force you to declare and size variables, and then use compilers to make the most efficient executable code possible do run faster, and there is advantage in that. But so long as you’re using an interpreted language (yes, I know… Python and its ilk are actually pseduo-compiled bytecode), you might as well get the full advantage of immaculately terse and readable duck typed code.

By Ref unless otherwise Stated.copy()

What else do I love about Python? Well, it made me finally understand the by-reference versus by-value that I found so ambiguous in other languages. In Python, everything is automatically a reference, and you have to ask explicitly to get a copy of a truly new copy of an object in memory using methods such as .copy(). I find that I get just a better understanding of what’s going on, and that it becomes harder to create accidental memory-bloat.

It is more likely that you will mangle your original objects in-place, resulting in instantly noticeable bug, rather than ones that slip quietly by, growing in size in the background until your system performance slows down. So, feel free to write recursive functions that pass objects to themselves. It’s kinda like the Star Trek transporters that can’t copy, except for the rare instances like when you’re Tom Riker in the Memory Alpha episode of Next Gen.

Star Trek Transporters Can't Copy

So you see, your already terse, readable code is simply less likely to cause memory-leaks by design. A principle similar to duck typing, where you are explicit, but only when you really need to be, is at work here. Things work by convention one way, and get overridden at the moment of the less-frequent exceptions—echo’s of what a “framework” is supposed to do. With mostly-good conventional behavior that only occasionally gets overwritten, Python feels a little like a framework. Not only is this an advantage for a beginner, but a seasoned pro can use all saved time that clearly understood conventional behavior provides to do more sophisticated feats.

Knowing that as a rule all variable-passing between functions never copies, but rather references the original object in memory is very liberating. It makes you understand a lot more about memory usage in your own code without all that explicit heap, stack, byref and byval nonsense that bogs down the code in other languages and burdens the programmer with precisely the type of housekeeping computers should be good at anyway. You get to intuitively understand the stack, realizing how all un-returned local variables get destroyed when exiting functions. Balloons inflate. Balloons pop. If you don’t carry that balloon around on a string, it’s going to pop. If you want a copy of an object in memory, you explicitly ask for it, and that turns out to be a more efficient place to be explicit than everywhere else in your code. Again, the upshot is that you get more terse, readable code.

Lists are just really well done in Python

Okay, now for the sexy bit. Many languages bill themselves as list manipulators, and have array or vector structures to represent and allow the programmer to interact with them. LISP, PERL and TCL are all known for this, with the L in LISP actually standing for this (and arguably, in PERL as well—pathologically eclectic rubbish lister). Lists in LISP are among the most basic building-blocks, from which almost everything is built-up making powerful meta-tricks possible that programmers like Paul Graham would argue are just not possible in other languages. Unfortunately, you have to be a pulsing-brain alien to use them.

Morbo LISP Lists

But there is another kind of list—easy-to-use containers for a series of values, often thought of as arrays. But the “list” container can be more versatile than a mere array, ready for countless general-purpose tasks, such as mini-databases of name/value pairs, FIFO/LIFO stacks and more. Such list-like array structures spare you from building them up from scratch in every program you need them (which is always) and inventing possibly inconsistent interfaces to them. Python employs the list concept as well, making it and its close relatives the dictionary (key/value hashes) and tuples (immutable list) into front-and-center features that heavily shape Python’s personality.

Python documentation sometimes call lists, dicts and tuples first-class data type objects, like a string or integer, just with plenty of built-in methods like iteration, popping, appending and sorting. All these structures can be arbitrarily nested for complex objects (jagged-arrays in other languages), and represented as ASCII strings (even when containing Unicode) making Python data ridiculously easy to transport—very similar to JavaScript’s JSON notation in which the string representation of an object is so readily swapped with the object itself in memory.

And even though it potentially deserves its own section in this article, I would be remis if I did not mention Python slices, which is basically just a string and object manipulation syntax whereby you eliminate the need for functions like instring, indexOf, left, right, mid, and all those other string-manipulation functions that make grabbing sub-strings so hard. In other words, if you want only the middle of “middle”, you would say “middle”[1:-1], which would chop off the first and last character to produce “iddl”. There is so much more to say here, such as pointing out negative indexes, but the astute reader should be able to infer all that. Slices work on strings and lists, and just makes everything about manipulating text and lists so much cleaner and terse.

The upshot of all this list stuff, is that the data-container mechanisms called for throughout nearly every programming pattern is built into Python, making some of the most common and tedious tasks in programming actually a pleasure to perform. Populate a list. Append and pop values. Grab sub-lists. Pass the whole thing as an argument to a function—no problem. Learn the interface to a list, and you pretty much know the interface to dict’s and tuples. Python quickly turns you into a list loving mad hasher.

Again, we encounter the concept here of Python having a lot in common with a “framework”—something usually added on top of a language. The parts of Python are built up just enough towards being a framework to spare you the desire to add yet another level of framework, and by being part of the core distribution, you can rely on these perfectly-sized building blocks being there in every Python program you write.

Yes, larger third-party Python frameworks like django are still there in the wings waiting to be a sort-of Ruby on Rails for Python, but I think I would recommend resisting django for awhile when taking up Python, just to appreciate for awhile how framework-like Python on its own already is. Python strikes this nice framework-balance without going overboard, with a gargantuan Class Library where you have to use obscure dot.this.dot.that notation in an insane sort of scavenger hunt just to do simple things, such as with Java or .NET.  Python is just chunky enough, with lists being the tastiest bits.

Files just become namespaces

Okay, time to talk code manageability. Many computer systems have the concept of modules and namespaces. In Python, these concepts are tied together, and latched onto the file. So, each file on the hard drive (or whatever) in a Python directory is a module that can be imported into any other file in that directory, automatically getting it’s own namespace that is the same as… drumroll, please… the name of the file! So in Python, you barely need to understand namespaces to get their benefit—you’re just sort of using them automatically—another big boon for collaboration.

Did I mention importing modules? Okay, here’s the part that blows my mind: you can keep re-importing the same modules all over the place with no loss of efficiency. Unless explicitly stated otherwise, the library is imported only the first time it’s needed, and subsequent imports merely reference the original import to make namespaces available. In other words, file A can import file B and file B can import file A, and there’s no problem with that. This will not create an infinite loop of imports, and in fact, it will have the desirable consequence of file A’s namespace being available in file B and visa versa.

This mutual importing as an encouraged technique to manage namespaces took me awhile to grok, but it was awesome when I did. Resultingly, some code nests module imports deep in a function, assuming the module will only be loaded into memory the first time it’s needed. Conversely, you can write one common file that does all your module imports, and import that in each of your other modules for a global resources approach.

The good, the bad, and the good again

Okay, if you’re thinking Python sounds fun, keep in mind that it was in fact named after Monty Python—and NOT the snake, as is commonly believed. So, instead of foo and bar, you will frequently encounter spam and eggs in example code, along with Knights who say ‘Ni’*3. And although Python was created by a single individual, Guido van Rossum, who managed to get himself hired by Google (which was developed partly in Python), the language is now maintained and advanced as open source by a committee, using Python Enhancement Proposals (PEPs). The community is willing to break compatibility with older versions when something really objectively needs to be improved.

One thing that really needs to be improved is the Urllib2 library. Just by its very name, you know that you need to be “in the know” that you shouldn’t be using the original Urllib—which is particularly a shame, because this is the first thing you want to do in Web Service programming. And even so, just to change the useragent of an http request, you have to go making functions that inherit from a superclass and override methods. That really sucks if you don’t know object oriented programming, which can be avoided in all other regards. Making simple http requests is much easier in Ruby, but this can be alleviated by adding the Request module, which I hope will be wrapped into the Python core libraries.

So, Python is not trying to be everything for everyone, and has its occasional annoyance. I think it’s just trying to be many things to most people while minimizing annoyances. Computer science types might be more satisfied with LISP or C that let you get “closer to the metal” to yield higher performance, or meta-languages with more robust support for anonymous functions, like LISP or Ruby, enabling certain things that are nearly impossible in other languages. Also, an optimized high-speed runtime environment isn’t on of Python’s strengths, nor is it undergoing the evolutionary pressure imposed by the browser JavaScript runtime speed arms-race, such as occurring with the Google V8 engine that made node.js possible, and whatever Microsoft and Firefox are doing.

One Language To Rule Them All

In fact, about the only reason I can think for a newbie to NOT take up Python is that you MUST learn JavaScript at some point, as the defacto standard way to do client-side programming for the Web browser. A year ago, this would not have been compelling enough, because you would still have to pick a different language for the server, but with the new node.js project, JavaScript is once again (since the now obsolete Netscape Server & Active Server Pages) a valid option for server-side programming—and possibly, the one language to rule them all. If your goal is to only ever have to learn one language, JavaScript might be your choice these days, with the advantage that you will be getting somewhat familiar with C and Java syntax—if you see that as an advantage.

And finally, Python’s fun, high accessibility to newbies, open source-ness and willingness to break compatibility would generally make most old-school programmers look on it with suspicion, and consider it not to be a “real” language—you know, one with a super-optimized compiler for creating binary executable. Well uh, while it’s not the norm, you can create binary executable with Python, and even so, it’s not trying or pretending to be C or C++.

But when the time comes to super-optimize your Python code, it does work quite nicely with either C or C++. Both can communicate with Python, allowing Python modules (files) to be swapped off with compiled C/C++ for hotspot optimization. This means that learning Python lets you flesh out applications quickly, speeding up development speed at the sacrifice of application speed. But when application speed becomes the priority, you can start swapping out bits with C, arguably making Python a productive step on the way to C.

Python is a language for which a newbie and pro alike can love. It can be a stepping-stone to C or C++, or an end in-itself. As an end in-itself, Python is different from most any other language, but in ways that yields great advantage, making it actually worth diverging from the mainstream. Yet, Python still manages to hang on as a mainstream language.

I’m not a professional programmer, but nearly everything I do directly demands programming, so I need a language I can take up again between long stretches of inactivity, without feeling like I have to chase the rabbit down into Wonderland to be productive again (as you do with languages with lots of overhead). Plus, following what I can only imagine to be a similar line of reasoning, Python is the first language to break LISP’s 20-year stronghold on MIT’s legendary introduction to computer science course.

It seems that in almost every discussion it seems that LISP is the exception to the rule—which is both its greatest strength and weakness. If you’re ready to chase that rabbit, LISP may be fore you. If you want one language to rule them all, JavaScript is currently your best bet. But if you want a nice, simple language for day-to-day use as a non-programmer that needs to program like myself, but want a language that can still take you as far as you want to go, then Python has a lot of advantages.

VN:F [1.9.14_1148]
Rating: 10.0/10 (3 votes cast)
Python Programming Language Advantages, 10.0 out of 10 based on 3 ratings

Related posts:

  1. Postpartum Pondering Programming Paradigms

Previous post:

Next post: