Like the first part of this book, this last part is a single
chapter, this time a short one to provide some parting context:
This chapter discusses Python’s roles and scope. It explores
some of the broader ideas of Python’s common roles, with the added
perspective afforded by the rest of the book. Much of this chapter
is philosophical in nature, but it underscores some of the main
reasons for using a tool like Python.
Note that there are no reference appendixes here. For additional
reference resources, consult the Python standard manuals available online
or commercially published reference books, such as O’Reilly’s
Python Pocket
Reference
and others you can find in the usual places
on the Web.
For additional Python core language material, see O’Reilly’s
Learning
Python
. Among other things, the Fourth Edition of that
book also explores more advanced API construction tools such as
properties, descriptors, decorators, and metaclasses, which we skipped
here because they fall into the core language category. That book also
explores Unicode text in more depth than we did here, since it’s an
inherent part of Python 3.
And for help on other Python-related topics, see the resources
available at Python’s official website,
http://www.python.org
, or search the Web using your
favorite search engine.
Foreword for the Fourth Edition
I wrote the following conclusion in 1995 for the first edition of
this book, at a time when Python’s integration role as a front-end
scripting language was viewed as more important than it often is today.
Since then, Python has emerged as one of the top four or five most widely
used programming languages in the world. As it has grown in popularity,
its focus on code quality and readability, and their related impact on
developer productivity, seems to have become the more dominant factor
behind Python’s success.
In fact, most Python programmers today write pure Python code,
without ever having to know or care about external libraries. Typically, a
small handful of developers integrate external libraries for the majority
to leverage in their Python code. While integration still matters, Python
is largely about quality and productivity to most people today (see
The Python “Secret Handshake”
for more on Python
contemporary philosophy).
Because of this shift, some of this conclusion may have grown a bit
narrow. In deference, I’ve removed all the “postscript” updates that
appeared here in prior editions. This edition retains the conclusion
itself, though, partly because of its historical value, partly because it
still reflects the ideals that propelled Python into the limelight in the
first place, and partly because of its continued relevance to Python users
who still integrate hybrid systems (well, that, plus the jokes).
At the end of the day, many of us have gotten off this chapter’s
proverbial island by now, thanks to the rise of tools such as Python.
Indeed, over the last 15 years Python has realized most of its original
aspirations laid out here. The choice before us today seems to be between
keeping the boat from growing too heavy or learning to swim well.
Well, the meaning of Python, anyway. In the
Preface
of this book, I promised that we’d return to the
issue of Python’s roles after seeing how it is used in practice. So in
closing, here are some subjective comments on the broader implications of
the language. Most of this conclusion remains unchanged since the first
edition of this book was penned in 1995, but so are the factors that
pushed Python into the development spotlight.
As I mentioned in the Preface sidebar, Python’s focus is on concepts
such as
quality, productivity, portability
, and
integration
. I hope that this book has demonstrated
some of the benefits of that focus in action. Along the way, we’ve seen
Python applied to systems programming, GUI development, Internet
scripting, database and text processing, and more. And we’ve witnessed
firsthand the application of the language and its libraries to
realistically scaled software development tasks, which go above and beyond
what many classify as “scripting.” I hope you’ve also had some fun; that,
too, is part of the Python story.
In this conclusion, I wish now to return to the forest after our
long walk among the trees—to revisit Python’s roles in more concrete
terms. In particular, Python’s role as a prototyping tool can profoundly
affect the development cycle.
This has to be one of the most overused lines in the business.
Still, given time to ponder the big picture, most of us would probably
agree that we’re not quite there yet. Over the last few decades, the
computer software industry has made significant progress on streamlining
the development task (anyone remember dropping punch cards?). But at the
same time, the cost of developing potentially useful computer applications
is often still high enough to make them impractical.
Moreover, systems built using modern tools and paradigms are often
delivered far behind schedule. Software engineering remains largely
defiant of the sort of quantitative measurements employed in other
engineering fields. In the software world, it’s not uncommon to take one’s
best time estimate for a new project and multiply by a factor of two or
three to account for unforeseen overheads in the development task. This
situation is clearly unsatisfactory for software managers, developers, and
end users.
It has been
suggested, tongue in cheek, that if there were a patron
saint of software engineers, the honor would fall on none other than
Gilligan, the character in the pervasively popular American television
show of the 1960s,
Gilligan’s Island
. Gilligan is the
enigmatic, sneaker-clad first mate, widely held to be responsible for the
shipwreck that stranded the now-residents of the island.
To be sure, Gilligan’s situation seems oddly familiar. Stranded on a
desert island with only the most meager of modern technological comforts,
Gilligan and his cohorts must resort to scratching out a living using the
resources naturally available. In episode after episode, we observe the
Professor developing exquisitely intricate tools for doing the business of
life on their remote island, only to be foiled in the implementation phase
by the ever-bungling Gilligan.
But clearly it was never poor Gilligan’s fault. How could one
possibly be expected to implement designs for such sophisticated
applications as home appliances and telecommunications devices, given the
rudimentary technologies available in such an environment? He simply
lacked the proper tools. For all we know, Gilligan may have had the
capacity for engineering on the grandest level. But you can’t get there
with bananas and coconuts.
And pathologically, time after time, Gilligan wound up inadvertently
sabotaging the best of the Professor’s plans: misusing, abusing, and
eventually destroying his inventions. If he could just pedal his makeshift
stationary bicycle faster and faster (he was led to believe), all would be
well. But in the end, inevitably, the coconuts were sent hurling into the
air, the palm branches came crashing down around his head, and poor
Gilligan was blamed once again for the failure of the technology.
Dramatic though this image may be, some observers would consider it
a striking metaphor for the software industry. Like Gilligan, we software
engineers are often asked to perform tasks with arguably inappropriate
tools. Like Gilligan, our intentions are sound, but technology can hold us
back. And like poor Gilligan, we inevitably must bear the brunt of
management’s wrath when our systems are delivered behind schedule. You
can’t get there with bananas and coconuts…
Of course, the Gilligan factor is an exaggeration, added for comic
effect. But few would argue that the bottleneck between ideas and working
systems has disappeared completely. Even today, the cost of developing
software far exceeds the cost of computer hardware. And when software is
finally delivered, it often comes with failure rates that would be
laughable in other engineering domains. Why must programming be so
complex
?
Let’s consider the situation carefully. By and large, the root of
the complexity in developing software isn’t related to the role it’s
supposed to perform—usually this is a well-defined, real-world process.
Rather, it stems from the mapping of real-world tasks onto
computer-executable models. And this mapping is performed in the context
of programming languages and tools.
The path toward easing the software bottleneck must therefore lie,
at least partially, in optimizing the act of programming itself by
deploying the right tools. Given this realistic scope, there’s much that
can be done now—there are a number of purely artificial overheads inherent
in our current tools.
Using traditional static languages, there is an unavoidable
overhead in moving from coded programs to working systems: compile and
link steps add a built-in delay to the development process. In some
environments, it’s common to spend many hours each week just waiting for
a static language application’s build cycle to finish. Given that modern
development practice involves an iterative process of building, testing,
and rebuilding, such delays can be expensive and demoralizing (if not
physically painful).
Of course, this varies from shop to shop, and in some domains the
demand for performance justifies build-cycle delays. But I’ve worked in
C++ environments where programmers joked about having to go to lunch
whenever they recompiled their systems. Except they weren’t really
joking.
With many traditional programming tools, you can easily lose
focus: the very act of programming becomes so complex that the
real-world goal of the program is obscured. Traditional languages divert
valuable attention to syntactic issues and development of bookkeeping
code. Obviously, complexity isn’t an end in itself; it must be clearly
warranted. Yet some of our current tools are so complex that the
language itself makes the task harder and lengthens the development
process.
Many traditional languages implicitly encourage homogeneous,
single-language systems. By making integration complex, they impede the
use of multiple-language tools. As a result, instead of being able to
select the right tool for the task at hand, developers are often
compelled to use the same language for every component of an
application. Since no language is good at everything, this constraint
inevitably sacrifices both product functionality and programmer
productivity.
Until our machines are as clever at taking directions as we are
(arguably, not the most rational of goals), the task of programming
won’t go away. But for the time being, we can make substantial progress
by making the mechanics of that task easier. This topic is what I want
to talk about now.
If this book has
achieved its goals, you should by now have a good
understanding of why Python has been called a “next-generation scripting
language.” Compared with similar tools, it has some critical distinctions
that we’re finally in a position to
summarize
:
Like Tcl,
Python can be used as an embedded extension language.
Unlike Tcl, Python is also a full-featured programming language. For
many, Python’s data structure tools and support for
programming-in-the-large make it useful in more domains. Tcl
demonstrated the utility of integrating interpreted languages with C
modules. Python provides similar functionality plus a powerful,
object-oriented language; it’s not just a command string
processor.
Like Perl,
Python can be used for writing shell tools, making it
easy to use for system services. Unlike Perl, Python has a simple,
readable syntax and a remarkably coherent design. For some, this
makes Python easier to use and a better choice for programs that
must be reused or maintained by others. Without question, Perl is a
powerful system administration tool. But once we move beyond
processing text and files, Python’s features become
attractive.
Like Scheme (and Lisp),
Python supports dynamic typing, incremental
development, and metaprogramming; it exposes the interpreter’s state
and supports runtime program construction. Unlike Lisp, Python has a
procedural syntax that is familiar to users of mainstream languages
such as C and Pascal. If extensions are to be coded by end users,
this can be a major advantage.
Like Smalltalk,
Python supports object-oriented programming (OOP) in
the context of a highly dynamic language. Unlike Smalltalk, Python
doesn’t extend the object system to include fundamental program
control flow constructs. Users need not come to grips with the
concept ofif
statements as
message-receiving objects to use Python—Python is more
conventional.
Like Icon,
Python supports a variety of high-level datatypes and
operations such as lists, dictionaries, and slicing. In more recent
times, Python’s notions of iteration and generators approach Icon’s
backtracking in utility. Unlike Icon, Python is fundamentally
simple. Programmers (and end users) don’t need to master esoteric
concepts such as full-blown backtracking just to get started.
Like modern
structured BASIC dialects, Python has an
interpretive/interactive nature. Unlike most BASICs, Python includes
standard support for advanced programming features such as classes,
modules, exceptions, high-level datatypes, and general C
integration. And unlike Visual Basic, Python provides a
cross-platform solution, which is not controlled by a commercially
vested company.
Like Java,
Python is a general-purpose language; supports OOP,
exceptions, and modular design; and compiles to a portable bytecode
format. Unlike Java, Python’s simple syntax and built-in datatypes
make development much more rapid. Python programs are typically
one-third to one-fifth the size of the equivalent Java
program
.
Like C
and C++, Python is a general-purpose language and can
be used for long-term strategic system development tasks. Unlike
compiled languages in general, Python also works well in tactical
mode, as a rapid development language. Python programs are smaller,
simpler, and more flexible than those written in compiled languages.
For instance, because Python code does not constrain datatypes or
sizes, it both is more concise and can be applied in a broader range
of contexts.
All of these languages (and others) have merit and unique strengths
of their own—in fact, Python borrowed most of its features from languages
such as these. It’s not Python’s goal to replace every other language;
different tasks require different tools, and mixed-language development is
one of Python’s main ideas. But Python’s blend of advanced programming
constructs and integration tools make it a natural choice for the problem
domains we’ve talked about in this book, and many
more.