You are on page 1of 180

Python

A Beginner’s Guide to Learning the Basics of Python

Programming

By James Patterson
TABLE OF CONTENTS

INTRODUCTION: What is Python?

CHAPTER 1: Python’s History
CHAPTER 2: Advantages and Disadvantages
CHAPTER 3: When To Use Python
CHAPTER 4: Installing Python
CHAPTER 5: Python Basics
CHAPTER 6: Python Versions
CHAPTER 7: Learning How to Count – Python Integers
CHAPTER 8: Python Strings
CHAPTER 9: Python Lists
CHAPTER 10: Tuples
CHAPTER 11: IF Statement
CHAPTER 12: While Statement
CHAPTER 13: For Statement
CHAPTER 14: Try Statement
CHAPTER 15: With Statement
CHAPTER 16: Other Statements
CHAPTER 17: Functions
CHAPTER 18: Classes
CHAPTER 19: Modules
CHAPTER 20: Python Idioms
CHAPTER 21: Performance Tips
CHAPTER 22: Implementations Galore

CONCLUSION

INTRODUCTION: What is Python?

Every programmer, programmer-wannabe, or person with just the slimmest brush with
programming principles has heard of Python. It is a “dynamic” programming language,
which has become one of the most popular of its kind, with Perl, PHP, and Ruby also
contending for the roost. Just like any of these or other programming languages, Python is
a unique and powerful language. Nowadays, it appears virtually anywhere—from scalable
web servers that run uninterrupted ‘round the clock, to throw-away scripts that only see a
few seconds of “daylight”. It can be used for both database and GUI programming, as well
as both server-side and client-side programming. It can be used by first-time coders just
stepping away from the basics, as well as by skilled developers in mission-critical settings.
It is certainly one of the most versatile of its lot.

Python allows for multiple programming paradigms, such as object-oriented, functional,
and imperative programming. There is also an automatic memory management and a
substantial, comprehensive, standard library.

Python interpreters may be downloaded and installed on many operating systems, which
makes the resulting code executable for different platforms as well. Using third-party tools
like Pyinstaller, the code can be repackaged into standalone and executable programs for
some of the most popular operating systems. This allows one to distribute software based
on the language to different environments—without having to install a Python interpreter.

For those looking for open-source, there is CPython—a reference implementation of
Python in the FOSS environment. It has a community-based model of development, like
its alternative implementations. CPython is being managed by the Python Software
Foundation, a non-profit outfit.

First Impressions

Python usually gives off two similar first impressions depending on who is viewing it. For
the experienced programmer, it looks strikingly similar to some of the more
“conventional” programming languages like Pascal or C. This is easy to explain, as
Python does borrow a lot from C. They even share many keywords, such as “if”, “else”,
“while”, and more. The rules are also shared between Python identifiers and their C
counterparts, with standard operators mostly having the same meaning.

This is, of course, not to say that Python is the same as C. There are several key
differences, such as the use of indentations instead of braces. This makes code essentially
easier to type, and more “user friendly”. This brings us to the second set of first
impressions, when Python is viewed by a complete beginner—it looks easy. Consider, for
example, the way that the standard “Hello, World!” line is printed in Python:

Print “Hello World!”

Now, check how this is written in regular JavaScript:

<script>
Alert(‘Hello, World!’)
</script>

Of course, a JavaScript code such as the one above needs to be embedded in an HTML
document to be effective. This is just a demonstration of how easy it is (comparatively) to
use Python for your programming needs. Python puts emphasis on code readability, with a
syntax that allows users to code in fewer lines than what others would allow. Programs are
optimized for clarity in both large and small scales.

Another way that Python differs from C is the fact that it uses dynamic typing. In C, the
variables should always be explicitly declared and then given a specific type (like
“double” or “int”). This data will then be used to do static compile-time checks and for
allocating memory locations for storing the variable’s value. In the Python framework,
variables are only names referring to the objects. The variables do not have to be declares
before they are assigned, and they can also change type at any time in the program. Like
most other dynamic languages, the type-checking will be performed in the run-time, using
an interpreter. This is in contrast with the separate compilation step used by some other
languages.

The reason Python seems so simple is because of its development path, carved in its
history.

CHAPTER 1: Python’s History

Many Python fans say that Python has quite a lot in common with the alphabet—most
commonly the fact that both start with ABC. Of course, in programming terms, ABD
refers to a general-purpose programming environment and programming language, first
developed in the Netherlands. The language was born at the Centrum Wiskunde &
Informatica (CWI). And while rarely talked-about today, it has as one of its greatest
achievements the merit of influencing Python’s design.

Python was first conceptualized by Guido van Rossum, back in the late 1980s. At this
time, van Rossum was working at a CWI project called “Amoeba” — this was supposed
to be a distributed operating system. He also worked on the ABC language, and he used
everything learned in this project to come up with Python.

Part of Python’s design grew with van Rossum’s frustrations with ABC. Like any good
innovator, he decided that he wanted a product with the same set of strengths, but without
any of ABC’s weaknesses. The first product of this endeavor was a simple set of virtual
machine, parser, and runtime. Van Rossum adapted the parts he liked about ABC, creating
syntax and data types such as a hash table, strings a list, and numbers along the way.

Rather than making a language with everything built into the core, Python was meant to
be a highly extensible language. It can also be embedded into existing apps that are in
need of a programmable interface.

What’s in the name?

As the project developed, its creator knew it had to have a name. Most people nowadays
believe that the name was derived from the world of snakes (as shown in the Python logo).
However, the name was actually derived from the famous British television sketch
comedy program, Monty Python’s Flying Circus.

At the risk of upsetting theorists, there is no real deep meaning to the name (as van
Rossum himself wrote in 1996). Apparently the name sprang forth during a particularly
irreverent mood as he looked for a name to describe his Christmas week project. He also
wanted a name that would appeal to the subset of Unix/C hackers. And of course, he was
also a fan of the said comedy.

The Python philosophy has been summarized in the neologism “pythonic”—a word that
can have many meanings related to this programming style. A pythonic code is essentially
something that uses the Python idioms well, and that shows minimalism and fluency. It is
also something that emphasizes readability. An “unpythonic” code, on the other hand, is
something that is difficult to understand or something that seems to be a rough translation
from another language.

Admirers, users, and adherents to the Python philosophy are hence called “Pythonists”,
“Pythoneers”, or “Pythonistas”.

The Python Philosophy

There is a set of rules that describe the Python philosophy, which has since then been
known as “The Zen of Python”. This was documented late into Python’s lifespan (in 2004)
by a programmer named Tim Peters. This set of 19 aphorisms aptly describe the way
Pythons works as a programming language, and has been initially created as an entry (the
20th) in the Python Enhancement Proposals. Any person into Python programming can
access this—the Zen appears as an Easter egg when entering “import this” into the
interpreter.

Below are the 19 aphorisms:

1. Beautiful is better than ugly.
2. Explicit is better than implicit.
3. Simple is better than complex.
4. Complex is better than complicated.
5. Flat is better than nested.
6. Sparse is better than dense.
7. Readability counts.
8. Special cases aren’t enough to break the rules.
9. Although practicality beats purity.
10. Errors should never pass silently.
11. Unless explicitly silenced.
12. In the face of ambiguity, refuse the temptation to guess.
13. There should be one—and preferable only one—obvious way to do it.
14. Although that way may not be obvious at first unless you’re Dutch.
15. Now is better than never.
16. Although never is often better than right now.
17. If the implementation is hard to explain, it’s a bad idea.
18. If the implementation is easy to explain, it may be a good idea.
19. Namespaces are one honking great idea—let’s do more of those!

This philosophy puts Python and fellow programming language Perl “at odds” with each
other, as the latter steers clear of the sparse and uncluttered grammar implemented by the
former. Perl explicitly aspires for the “there is more than one way to do it” philosophy,
which Python users claim invite unnecessary confusion into the coding.

Part of the Python philosophy is the dislike for premature optimization. Python’s
developers reject patches to the non-critical parts of the language if it means the marginal
increase in speed is offset by the loss of clarity. When speed is desired, a programmer can
instead move the time-critical functions to different extension modules written in other
languages (like C). There is also a “just in time” compiler (PyPy) available.

And of course, there is another goal that Python’s developers have is to make the language
as fun to use as possible. This is also reflected in how the language was named. Even
tutorial and reference materials are approached with a playful outlook. For example, some
exercises refer to Monty Python-inspired spam and eggs instead of the standard foo and
bar.

Python’s Development

The first version of the Python code was published at alt.sources (version 0.9.0 was its
number) back in February of 1991. This was quite remarkable as a first release since it
already handled exception handling, some core data types, and functions. It had a module
system, and was object-oriented.

In January of 1994, Python’s version 1.0 was released. This included some major
improvements such as new functional programming tools map, filter, reduce, and lambda.
After six and a half years, in October 2000, Python 2.0 was born, which in turn included a
full garbage collector and new list comprehensions. The new release was also supporting
Unicode.

In the next 8 years that followed, Python version 2.x grew leaps and bounds in popularity.
Each of these releases was backwards compatible with the previous Python release. This
continued until the introduction of Python 3.0 (also known as Python 3000 or Py3k).
Aside from not being backwards compatible, Py3k emphasized removing duplicate
programming modules and constructs. This is in fulfillment (or, at least, close fulfillment)
of the 13th Zen—“There should be one—and preferably only one—obvious way to do it”.

Here are some of the prominent changes in Py3k:

Print has now been turned into a function.

The system now uses views and iterators instead of lists.


The rules for ordering the comparisons are simplified. For example, a

heterogeneous list may not be sorted, since all the elements of the list should be
comparable to each other.
There is just a single integer type left.

When two integers are divided, a float is returned instead of an integer. However,

one can use “//” to have the old behavior.
Instead of Unicode vs. 8-Bit, there is now a difference between Text vs. Data


The development process throughout all these years is conducted through the PEP or
Python Enhancement Proposal process. This is a mechanism that the developers use to
propose for new features, as well as for collecting community input on any issues. This is
also used to document the design decisions that have been built into Python. Any
outstanding PEPs are in turn reviews, commented upon, and subsequently worked on by
the community and by van Rossum himself (Python’s Benevolent Dictator For Life).

The language enhancement goes along with CPython development and its reference
implementation. The “python-dev” mailing list is considered the primary forum for
discussion about development. Any specific issues are to be discussed in a “roundup bug
tracker” that is maintained at the project’s website (python.org). There is also development
taking place on a self-hosted repository of source code, which runs Mercurial (a
distributed revision control tool).

There are three types of public releases from CPython, distinguished by the part of the
version number which is incremented. First are the backward-incompatible versions
which happen when the code is expected to break (hence demanding manual porting).
Here, the first part of the version number will be incremented. These releases are fairly
infrequent. Version 3.0, for example, was released a full 8 years after the preceding
version.

The next one is categorized as “feature” or “major” releases. These are largely
compatible, even though they introduce new features. The second part of its version
number will then be implemented. These are scheduled to go out about every 18 months,
and are then supported by bugfixes for the next several years after its release.

Lastly, there are the bugfix releases, which do not have any new features. However, they
fix known bugs, providing more stability to the users. In this release, the last part of the
version number is instead incremented. The releases are made when there is enough
number of bugs fixed upstream ever since the last release (coinciding with roughly every
quarter). Any security vulnerability will also be patched in a bugfix release.

There are also some alpha, beta, and release-candidates that are sent out as previews for
testing before a final release is announced. There is, however, a rough schedule that is
followed for the releases, even though this can be pushed back if an issue renders the code
not ready. The developers will monitor the code’s state by running large-scale tests during
development. This is usually done through the BuildBot continuous integration tool which
helps in automating the compile/test cycles needed to validate any change to Python’s
code base.

As of January 2016, the Python development community has contributed more than
72,000 software modules to the PyPI, the Python Package Index. This is the official
repository of third-party Python libraries. Major academic conferences are also held, such
as PyCon (currently the largest of its kind). There are also mentoring programs available,
like Pyladies, which is an international mentorship group meant for women who desire to
actively contribute to the Python development community.

Development Environments and Implementations

Most of the Python implementations, like CPython, function as command line interpreters
for which users enter statements in sequence. In return, results are immediately shown.
Basically, Python acts as a shell.

To add capabilities, other shells beyond those provided by the basic interpreter may be
used. These include IDLE and IPython. While following the Python shell’s visual style,
they also implement other features such as auto-completion, session state retention, and
syntax highlighting. There are also other standard Python IDEs for the desktop, just as
well as there are IDEs for the browser. Other options include Sage (meant for creating
math and science-related Python programs) and PythonAnywhere (a browser-based
Integrated Development Environment which doubles as a hosting environment.

Python Implementations

CPython, which is the main Python implementation, meets the C89 standard and is written
in C. It is used to compile the Python programs to intermediate bytecode, which can then
be executed by a virtual machine. It has a large standard library written both in C and
Python. It is also available for multiple platforms including Microsoft Windows (XP
support had been dropped, however) and most Unix-like systems. This proves the cross-
platform philosophy that was present since Python’s inception.

As previously mentioned, there is also PyPy, an interpreter for Python 2.7 and 3.2 which
has gained reputation for speed (over CPython) and compliance. There is also a version in
the pipelines that aims to increase speed by using software transactional memory to take
advantage of multi-core processors.

Stackless Python is another implementation, coming as a significant port of CPython. It
does not utilize the C memory stack, instead implementing microthreads. This allows
hugely concurrent programs. It is to be noted that PyPy also comes in a stackless version.

Aside from these, there are other just-in-time compilers that have since fallen into hard
times (i.e., lack of developmental support). One comes from software giant Google, which
launched the Unladen Swallow project back in 2009. This had the original aim of
increasing the speed of the interpreter by at least 5 times through the LLVM (Low Level
Virtual Machine) infrastructure. This improves the ability to multi-thread, allowing scaling
for up to thousands of cores.

There is also the “specialising just in time compiler” called Psyco, which integrates with
CPython. This transforms the bytecode into machine code at the runtime. This produces a
code that is specialized for specific data types which can also run faster than standard
Python codes.

Google is far from being the only big name to dabble in Python compilations. Back in
2005, mobile phone company Nokia also released its own Python interpreter for its Series
60 mobile phones. This was called Psy60, which included a lot of the modules from
CPython along with added modules for Symbian OS integration. This project, unlike the
Google counterpart, has been kept mostly up to date with many third-party modules
available. The Nokia N900 even supports the language with its GTK widget libraries,
allowing programs to be written and run on the phone itself.

There are also different compilers available to high-level object languages using as its
source language unrestricted Python, its restricted subset, or a language similar to it.
Examples are:

Jython, which compiles the language into Java byte code. This can then be

executed by any implementation of the Java virtual machine. This will also enable the
use of Java library functions from the program in Python.
IronPython, which follows an approach similar to Jython except that it runs

programs on the .NET CLR (Common Language Runtime).
RPython, which can be compiled into Java bytecode, C, or Common Intermediate

Language. It is also used to build the PyPy interpreter.
Pyjamas, which is used to compile into JavaScript.

Shed Skin, which can be used to compile to C++.


Pyrex and Cython, which can be used to compile to C.



Discussion on different Python implementations can be very lengthy, and we will be
reserving that as the final chapter of this book.

CHAPTER 2: Advantages and Disadvantages

Of course, Python is far from being the only programming language you can use for your
coding needs. But why should you choose it? Here are some of the most common reasons
Python is recommended:

Easy-to-learn Syntax. It doesn’t matter if you have been acquainted with other
programming languages before — both programmers and non-programmers can use
Python easily because of its syntax.

Readability. If ever you need to take apart a code that someone else wrote (either for
study or troubleshooting), you can easily do it due to the clear readability of the
programming language. In fact, there are some who refer to Python as an “executable
pseudo-code” due to its syntax following natural language used by real humans. This gets
rid of the verbosity and formality used by other languages, and also goes as close as
possible to the way programmers habitually outline their ideas. This bring Python
inherently close to the very simple “pseudo-code” programmers use to outline their
thoughts and solutions to other programmers. Even programmers who write in other
languages are given to using Python as a testing ground wherein they can test their code
before implementing it in a different language.

High-level Usage. Unlike the inscrutable low-level languages, Python allows you to code
a lot faster.

Object-Oriented. In a nutshell, object-oriented programming lets a user create data
structures which can then be re-used. This reduces the amount of repeated work that needs
to be done. Languages often define objects with namespaces, which can then edit
themselves using certain keywords. Python shares this distinction along with other
languages such as Java, C#, and C++. Object-oriented languages can also be used to
design almost any type of non-trivial software, which can in turn be implemented in any
scripting or programming language. A good example lies in a number of Linux kernel
features, which feature objects. These implement their own encapsulation of data structure
and behavior through pointers to functions in C. New programmers benefit greatly from
Python’s support for object-oriented programming since the same concepts and
terminology used in its study will invariably appear in the work environment. In case the
new programmer decides to learn a new language, the same object-oriented concepts can
still be used.

Free of Charge. Being a Free and Open-Source Software (FOSS), Python is accessible to
anyone. The pre-made binaries are distributed by the Python Software Foundation, and the
code can also be modified and re-distributed as allows by the CPython license.

Cross Platform. As has been mentioned before, Python is available on all major operating
systems—MS Windows, Mac OS X, and different flavors of Linux.

Wide Support. Like any good open-source project, Python has an active community that
is complete with different forums, websites, mailing lists, and news groups that also attract
knowledgeable contributors from different tech scenes.

Safety First. Unlike other languages based in C, Python does not have any pointers. This
makes the language much more reliable. Errors also never silently pass unless this is
explicitly ordered. This will allow the user to read and see why the resulting program
crashed, allowing efficient error correction.

All In. In the language of many coders, Python has been known as the “batteries included”
language. This means that there are more than 300 different standard library modules that
contain both classes and modules for a large subset of programming scenarios. Some of
these include creating temp files, mapping the files into memory (through anonymous and
shared memory mappings), spawning sub-processes and controlling them, decompressing
and recompressing files, accessing indexed database files, and a lot more. These libraries
can also offer interface to various GUI, as well as send emails, and parse web pages. With
less than a dozen code lines, a person can create a custom web server using the Python
language—powered by one of these standard libraries.

Greatly Extensible. Aside from the standard libraries, there are also extensive collections
of add-on modules that are freely available. There are also frameworks and libraries, as
well as toolkits that all conform to conventions and standards. As an example, nearly all
the database adapters (used in talking to any client-server engine like Oracle, MySQL,
Posrgres, etc.) conform to Python DBAPI, thus allowing users to access them using the
same code. This makes it easy to modify Python programs to support any type of database
engine.

Disadvantages

Then of course, like with any programming language, not everything is a rosy walk in the
park. There are a couple of disadvantages in it that one should still watch out for as he
learns:

Speed. Unlike languages that need to be separately compiled and then executed, Python is
executed by an interpreter. This causes it to be slower. For most applications, this will not
pose a problem. However, there are certain instances when an increase in speed is
desirable. This brings up one idiom coined by Python users: “Speed is not a problem until
it is a problem”.

Simple Rules. Python is a very easy programming language. However, when one has
mastered it, one can be too accustomed to its features especially its late-binding dynamic
models and its extensive libraries. Thus, when shifting to a new language that does not
have these, the user may run into difficulties adjusting. In other languages, one typically
has to declare the types of variables first and then cast values from this type to another.
There are also requirements for adding curly braces and semi-colons (as well as other
syntactic differences) in other languages that a Python user may take for granted.

CHAPTER 3: When To Use Python

Each programmer has his preferred language, and decisions on which to use often come
subjectively based on experience and preference. In fact, this sometimes doesn’t matter, as
most of the modern languages can perform the majority of the programming tasks. They
also mostly include the needed libraries that might be useful for day-to-day tasks. There
are other times when concerns about interoperability can dictate one language over
another (as well as a platform over another), but in modern times this is commonly solved
by shared SQL databases, XML interchange, and web services.

Therefore, when choosing whether to use which language for your programming needs, it
is important to look at the way that the language is designed—what makes it easy to use
for your purpose and what impediments it may present. If the performance and features
are moot points of argument, then other more intangible items such as elegance and “feel”
should be more carefully considered.

That said, Python is often praised for being one of the languages that can make
programmers feel more productive. It can “glue” together different applications quickly,
too, and its more minor details have attracted legions of fans—and haters—from all over.
Sometimes, all the opinion around Python can distract potential users from the careful
consideration of when to use it—this chapter is meant to address this.

For many developers around the world, Python has evolved into the default scripting
language choice. Some consider it rare that a programmer starts in Python and then
suddenly discovers that the language is inappropriate—but it can happen, even if Python is
scalable both in performance and project size. The general degree of freedom that the
simplicity of the language allows would also mean that sometimes programmers would
have to be more disciplines in the way the code is structured.

On the Desktop

A programmer can write applications on the desktop using Python. This can be
accomplished through frameworks like PyGTK or WxPython. Take note, however, that
most desktop applications are still coded in compiled languages like C, C#, or C++. These
languages have frameworks that commonly have more sophisticated tools for
development. Thus, the resulting programs are usually easier to distribute, without
requiring the user to install Python first.

Python has been blessed with good tools for graphical development, including Eclipse
PyDev and Wing IDE extensions. However, in reality, most of the Python developers work
in a style reminiscent of the UNIX operating systems — through terminals and standalone
text editors. On other platforms like .NET or Java, the environments like the MS Visual
Studio will always have a tighter integration with the language. Whether this is a good or
bad thing, however, will depend on individual experiences.

Python on the Web

Much clamor has surrounded the alleged movement of Java programmers to Ruby-on-
Rails, allegedly due to them getting tired of Java’s overhead and enterprise frameworks.
While this may be true, this may also be the fruit of good marketing from the Rails
proponents. In fact, Python also boasts of the same benefits as it has.

There are several rapid and successful web app frameworks available for the Python
language, each of them with their own slant. There are also those that even share the same
components. Some of the most popular include Pylons, Django, CherryPy, TurboGears,
Grok, and Zope (from which Grok is based). These can all be used for serious Python
applications. For example, Zope was conceived as an open-source app server, pioneering
its field and proving that Python is viable even in enterprise environments. This is despite
many Python proponents claiming that the idea has recently become “unPythonic”.
Another popular open-source implementation is Plone, a content management system
running on Zope and implemented in organizations like Oxfam and Novell. Pylons is the
stuff that runs high-traffic Reddit.com, and Django sits under the hood of Revver.com.

Deploying web applications in Python is mostly a straightforward affair, even though it is
not quite as simple as PHP application deployment in Apache. Object/relational mappers
like SQLAlchemy cater to database connectivity very well. However, most of the web
frameworks of Python have yet to catch up to Java or .NET when it comes to enterprise-
grade app servers — the latter two offer better support for failover, high-availability
clustering, and server management.

.In Enterprise Settings

Most large companies and organizations have a standard development scheme on either
.NET or Java—the two platforms seen by many to be best suited for enterprise
applications. There is a general belief that using these will help improve the
interoperability of the deployments while also lowering the maintenance costs. While
Python usually does not operate in the same level of scale or ubiquity, it stands as a very
useful complement. It even stands as a solid alternative when the platforms mentioned
above prove inappropriate.

The common enterprise platforms are usually—and by necessity—very large and very
complex. They usually depend on more elaborate tools to allow programmers to manage
the code, deployments, and subsequent builds. In many applications, this may be overkill.
Ideally, programmers should be able to take any language that captures their fancy when
the inspiration to code hits them. Python’s immediacy allows it to be perfect for such
common automation tasks, quick prototyping, and similar purposes. There are also many
developers who feel that Python can give one the leeway to move beyond mere
prototypes, without having to scratch all of their previous work.

This considered, Python can prove to be useful for large and complex systems. For
example, YouTube runs mainly on the Python language. It is also a preferred language at
many organizations, like NASA, Google, and Industrial Light and Magic. There are
specialized frameworks and Python libraries for scientific work, web services, data
manipulation, XML interchange, and lots of other things.

All is not sunshine and rainbows, however—the main disadvantage of Python in such
enterprise settings is that programmers are usually scarcer than in other languages like
Java. While Python is very easy to pick up for a seasoned programmer, the wealth of
specialized training courses, books, and even certifications available in Java are yet to be
matched by the language.

On top of this, the sheer expressivity and power that is offered by Python would mean that
it takes a seasoned developer to create a sterling product. By design, C# or Java are more
restrictive. This forces the programmer to stick to stricter rules, commonly revolving
around interface compliance and type safety. For others, this can hinder productivity. Still
for some, this is ideal in reducing the mistakes and accidents of design.

Lastly, concerns regarding application integration can dictate the prevalence of a specific
platform or language. In the service-oriented and heterogenous landscape today’s systems
live, it is usually possible to write a Web service using Python while allowing it to plug
into a service bus from Java. In the end, this can be consumed by a program in Visual
Basic—and we are just scratching the surface.

Internal Compatibility

Python has had a long history, as we had covered. However, compatibility has not been a
real concern—at least until the branching of Python 2.x and 3.x. In fact, programs that
were written for Python 1.0 can still run smoothly on at least up to Python 2.5. Python has
been very committed to supporting existing users of its language, with a community large
enough to withstand the pressure of diverging paths.

Use Python when…

Python should be primarily considered when the following conditions present themselves:

When you need a proven, reliable, and general-purpose scripting language

complete with an extensive standard library.
When you need a language that can be useful across different programming-

related tasks, from web apps to shell automation.
If you are familiar with and like the syntax and philosophy of Python

And of course, if you find the language fun aside from being productive.


On the other hand, consider the following as red flags for choosing Python—or at least as
reasons to consider using a different language:

When you are building a massively parallel or embedded system, which would

not benefit from a scripting language (mainly due to the latter’s concerns about
execution speed).
When you are primarily building desktop apps, especially if it will be deployed

on Windows. Usually, other platforms (specifically .NET) offer more robust tools
as well as easier distribution paths for the final software.
If you are working with a team of less-experienced programmers. They may be

better off benefiting from the plethora of training for other languages like Java.
Also, they are a lot less likely to commit mistakes when using type-checked,
compile-time languages.
If you have needs that may be better served by a specific language aside from

Python. For example, if you know Perl and you have to do a lot of text processing,
then that might be more ideal.

CHAPTER 4: Installing Python

In the first chapter, we went into detail about the different implementations of the Python
programming language. Before one can successfully code, one has to make sure he has the
necessary tools—that means getting Python into your device. If you are lucky (read: if you
have the right operating system), you might not even need to download it as it might have
come pre-installed. If you wish to check if you already have Python, simply open up your
system’s Command Line Interface (CLI) and type “python” (minus the quotes). If you see
a response—typically comprised of the word “Python” and some build information with
the version number—then you are good to go. For example, here is an example of the
response that would show up when using a 32-bit Windows XP:

Python 2.7.2 (v3.4.2:ab3c023a9432, Jan9 2016, 10:11:04 [MSC v.1600 32 bit (Intel)] on
win32
Type “help”, “copyright”,”credits” or “license” for more information.
>>>

Or if you are using Win 7 64-bit, then you will see the following response:

Python 2.7.2 (v3.4.2:ab3c023a9432, Jan9 2016, 10:11:04 [MSC v.1600 64 bit (AMD64)]
on win32
Type “help”, “copyright”,”credits” or “license” for more information.
>>>

In case you get an error as a response, then you will need to download Python first.

Downloading Python

Fortunately, downloading Python is a breeze. It is recommended that you get the latest
version, if possible in the 3.X series (since it is the one that gets the most active
developments). If you prefer, you can still get the 2.X branch. Be reminded, however, that
no future development of this branch is planned (with the most recent release being way
back in 2010). The major implementation (CPython) is available on
www.python.org/downloads/

Windows and Mac OSX users can easily download an installer which will do all the work
that is needed to get Python to your system. If you instead use Linux (or another Unix-like
operating system), then you can build the binaries from the source code itself. There are
some distros in the Linux world that allow Python to be installed more easily, coming in
the form of pre-made binaries. For many of the most popular Linux distros, documentation
should be available on the website.

Also, do not skip ahead to this step without trying out the previous one—checking your
device for any pre-installed versions of Python. Note that most Linux and Mac machines
already come with a form of Python installed—almost always the 2.X branch. Remember
that this is not compatible with 3.X, so if you wish to upgrade you can still download.

Python Online

In case you are working from a different device, or if you decide that downloads may pose
a security risk, or in case you just want to work online for any reason — you’re in luck.
An interactive shell for the language is offered by the Python Software Foundation. This
comes by the name PythonAnywhere, and is available on their website. This has more
implementations than vanilla CPython, and as a plus no download or reinstallation is
required. On the other hand, you will not be able to execute scripts and files from this
shell, hindering the more advanced Python learners.

CHAPTER 5: Python Basics

The Shell

There are many ways to call it—command prompt, shell, prompt, command line, CLI—
but they all pertain to the same entity. This is one of the mediums of communication
between the user and the Python interpreter. For a good part of this book, most of the
Python codes seen in the examples will be done in the shell.

When starting up the shell, do the same thing you did for testing whether or not your
machine has Python on it—namely, pull up the CLI and enter “python”. You will see the
details we laid out above—the version number, date of build, compiler used for the build,
the computer architecture, as well as the operating system. The information will be useful
for debugging, as well as for checking which version you have on hand.

From the initial text display, one of the things you will need to pay attention to is the set of
three greater than signs (“>>>”). This will tell you that a prompt is present, asking for
input. This prompt will always be shown in the examples we will be using, so it is not
something you will have to type out.

For example, here is a code with the prompt displayed:

>>>print(“Hello, world!”)
Hello, world!

As with the information above, the new line that appears without the prompt is the output.
You will also notice that the prompt will change into an ellipsis (“…”) when you enter a
command that has indentations. You will have to be careful not to see this as part of the
actual code:

>>>if True:
… Print(“Hello, world!”

Hello, world!

The Script

Once you have got the hang of Python programming, you will find that you find it tedious
to repeatedly type the same programs into the shell. Like all its sibling interpreted
programming languages, you will be able to store and execute the Python code directly
from a file.

There are two different types of Python files—plain text and bytecode files. “Plain text”
files are so-called since they are simple files that are created and edited using any simple
text editor. This may be the Windows-standard Notepad, or a downloaded utility such as
Notepad++, Sublime, Kate, or even Python’s very own IDLE or IDE. The bytecode file, o
the other hand, is a compiled CPython file. We will go into more detail about these files
later on in the book.

Then, there is the third type of file—the Python script. This is usually suffixed with the
extension “.py”. It is as executable as anything you type in the Python shell when it is
executed by itself—this goes for most operating systems (Windows, Mac, and major
Linux distributions included). Here is an example of a very simple script that we can title
“greeting.py”:

Print(“Hi there! I am a Python script!”)
Input(“Press enter to continue…”)

Take note that things may be a little different depending on whether you are using Linux,
Mac, or Windows. For users of Linux, Mac, and other operating systems derived from
UNIX, you will need to include a “shebang” at the beginning of the script. For Python,
you will need to include the following line:

#!/usr/bin/env python

This line tells the shell where the interpreter lies. One good thing about this is that it starts
with the hash tag (#). This is ignored as a comment on other operating systems whose
scripts do not require the use of a shebang. This means that you can take any code written
in Mac or Linux and execute it in Windows without worrying about the Windows
interpreter misinterpreting the shebang!

For Windows users, you will have to remember that Python files have to be executed with
py.exe. This will start by default with the Python 2.X branch, if installed on your
computer. Executing “py” should tell you which version you have running. If you
currently have 2.X but are in need of the 3.X branch, you will need to us a switch—“-3”.

In order to make Python 3.X as the default version, you will need to open up the control
panel, then create an environment variable “PY_PYTHON”. Set the value of this variable
to 3. Rolling back to 2.X is as simple as deleting PY_PYTHON and changing the value to
2.

Running the Python script can be done either by clicking on it or by running it from the
system’s shell, regardless of which operating system you are using. The script sample
above, for example, should give you the lines “Hi there, I am a Python script!” and “Press
enter to continue…”. The script will then pause up until you actually press the Enter key.

If you tried this, then congratulations! You have just built your very first Python script!

Another note on saving Python scripts in Windows, there are some users who might not be
allowed to save directly to a “.py” extension. In this case, you can create a text file then
just save it with .py afterwards. Or, you can also change the “Hide extensions for known
file types” toggle in your Control Panel. This can be found under the Folder Options.
Other more advanced options are available, but these should suffice for our current
purpose.

IDLE

Earlier, we talked about IDLE, or the Integrated Development Environment. This is the
default IDE that is installed when one gets CPython. On the Windows OS, this may be
accessed by right-clicking any Python scrips, then selecting “Edit with IDLE” on the
context menu. You can also open up IDLE directly from the CLI by typing “python -m
idlelib”.

When using IDLE, a couple of things will be noticeable. First, you will find that the code
is colored—strings are green, comments are in red, functions (built-in) are purple, and so
forth. This will allow you to have a visual cue of certain parts of the code, a significant
advantage over mono-colored text. Second, you will also find that IDLE would make
automatic indentations where needed. It will also modify the function of the Tab key—
inserting four spaces when pressed.

For those just starting out, these default settings are perfect for learning the ropes.
However, your preferences may change when you have reached the intermediate to
advanced stages. To meet these changing requirements, the creators of IDLE made it into a
very customizable module. For example, the red-and-green distinction may not work too
well for a color-blind person, so the colors can be swapped out for something else. The
default settings can be changed in the Options menu, in the menubar.

Basics and Jargon

Now that you know the very basics and the tools available to you, it is time to tackle some
of the more commonly-mentioned jargons and other stuff. More advanced items will be
tackled later on, but pay close attention to these starters:

1. In Python, a “comment” is any text preceded by a hashtag (#). This is meant to be a
sentence that is readable by humans (e.g., a note for yourself or for a fellow programmer)
but unreadable by Python. For example, writing something that says “# For your eyes
only” will appear on the code but will be ignored by Python upon interpretation.

2. Once you start seeing an ellipsis (…) or three greater-than signs (>>>), then this will
mean that you are dealing with the Python shell.

3. “Variables” are namespaces such as “somevar” and “var” (or anything you define). It
can hold Python data types, such as numbers or strings. More about this will be discussed
later.

4. If you are following the steps in this book to the letter but keep on seeing error
messages, double-back and check the Python version you are using. Remember that the
exercises here are meant to work on Python 3.X.

5. Don’t confuse the term “Python script” with the actual programming we are about to
do. Essentially, the Python script is just a plain text file that has a Python code in it.

CHAPTER 6: Python Versions

Before we proceed with all the coding, there is another thing that we have to clear up—the
different versions of Python. Throughout this book, you will be seeing examples and
suggestions that will only be effective for a specific Python version. This is especially true
when we get to the optimization section towards the end. You will inevitably ask: “Which
Python version should I be using?”

Here’s the (extremely) short version of things: Python 3.X is the present and the future of
Python, while 2.X is the legacy.

What’s the difference?

As mentioned, the last version of the Python 2.X branch—2.7—was released back in
2010. There will be major releases after. However, Python 3.X is still being developed
(very) actively, and is currently in 3.5. All of the most recent standard improvements for
the library, for example, will be available only in 3.X.

However, despite the improvements of 3.X (better Unicode, turning print and exec into
statements to scratch the surface), the broader ecosystem of the programming language
has already amassed a huge amount of add-on quality software through its years of
growth. The downside of being in bleeding-edge 3.X is the lack of backwards
compatibility, therefore losing you the ability to use some of these fine software
(especially those done in-house in companies).

So which version should I try to use?

For starters, you should best stick with what is on your PC—what you get with the
previous chapter would be it. This will allow you to just explore the basics of Python,
since you can always upgrade later. For most of you, that would probably mean starting
with Python 2.7.

Now, what if you’ve already progressed beyond the basics? How do you choose whether
you wish to continue with the 2.X or the 3.X branches?

As is common, the version you want to choose will greatly depend on what you want to
do. You may first try getting Python 3.X and see if you can do everything with it. There
will be a few downsides, which will include a slightly worse support for libraries. If you
are creating software for mass distribution, be mindful that you will also need to have your
users install Python 3.X. The bleeding-edge Python will also suffice if you will be writing
things which will use none of the Python 2.X modules. On the upside, Python 3.X has
been known to correct some quirks that are usually blockers towards learning Python.

However, there are also certain scenarios where it will be better for you to stick to legacy
Python. This is primarily if you will be developing for an environment that you have no
control over. These environments will usually impose their own specific versions, which
will not allow you a free selection from the currently available ones. Also, you might
come across the need to use a third-party utility or package which has not yet been ported
to the latest branch. Sometimes, you may be able to painlessly port these packages, but
this is not always the case. In these times, you should stick to Python 2.X to retain full
access.

A popular module that has not yet been ported to Python 3.X (as of time of this writing) is
Twisted—useful for networking application. Most of the other libraries—so long as they
are actively maintained—already have people working to make them available for
bleeding-edge support. However, some other libraries have other priorities—for example,
Twisted focuses more on its production servers where the older Python support is more
important. Supporting a brand-new version with major changes is put far back on the back
burner, since the porting process is far from trivial.

Other more common modules that have already been ported to Python 3.X include Tkinter
(for the creation of GUI applications), PyQt, PySide, and PyGObject (for the creation of
GTK+ GUIs). Here are other packages already ported to Python 3.X:

Numpy. This is useful for number-crunching.
Django, CherryPy, Flask, and Pyramid. These are useful for web sites.
PIL (now Pillow). PIL was an image processing module which has been replaced by the
Pillow fork for Python 3.X support.
Cx_Freeze. This is useful for packaging the applications complete with their
dependencies.
Py2exe. This is great for packaging the application for Windows OS users.

If you find Python 3.X fun to use but are afraid of possible dependency issues, then it will
be a good to do some extensive research. Note that much of the modern code written using
Python 2.X should not be largely changed in Python 3.X. A sterling example will be any
code written to inter-operate with GUI and web frameworks that will force aps to
distinguish text and binary data.

Note as well that if you will be using an alternative Python implementation like Jython,
Pyston, IronPython, and the like, you might find that there is a relative scarcity of support
for Python 3.X. This might be a good consideration if you wish to choose such
implementations, since you will have to think twice about performance and/or integration
with other systems.

Python 2.X makes its case

As a simple Internet search will tell you, those who wish to stick around to Python 2.X are
in the minority. A greater chunk of the Python community believes that the future of
Python lies in its latest release. After all, it was the one that took out all the mistakes of its
predecessors.

However, this is not 100% true. In fact, some of the improvements (notably the less-
destructive ones) have been backported from 3.0 and 3.1 to 2.6 and 2.7 respectively. Only
the following features are available exclusively on the 3.X fork (note that this is a non-
exhaustive list):

● Default Unicode strings
● Clean separation between Unicode and bytes
● Function annotations
● Exception chaining
● Keyword-only arguments syntax
● Non-local variable declarations
● Extended tuple unpacking

All this considered, any well-written code in 2.X can still be much like 3.X. This can be
many different things. A good example is the use of the xrange function for an optimized
Python 2.X code. The xrange has disappeared in Python 3.X, but is has formed the basis
for the new range implementation. You will see how this is applied towards the end of this
book..

Bottomline? As a programmer, the best way to optimize the code is still not to pore over
the strengths and weaknesses of each branch. Especially for those new to the language, the
emphasis should be on the writing of good code. The tools with which you write it will
only be useful if the code itself is clean.

I use Python 3.X, but there’s this library available only on 2.X. Do I change to 2.X, or
should I quit on the package?

If you do not have other packages that may serve as alternatives, then you will have a few
other options:

● Port the entire library to Python 3.X.
● If that is too hard, you can instead start off with 2.X. Then you can switch to 3.X
painlessly so long as the code is good and every needed dependency has been ported.
● Decide if that feature which requires the library is integral to your program. If
not, then perhaps you could drop it.

The best resort is, of course, the first. Oftentimes, you might even find that someone is
already undertaking the process of porting the library to 3.X. If that is not the case, then
you can start it. While porting is not always easy, it is still a lot easier than having to write
everything from scratch.

I had written code in 3.X, and now it has to be used by someone with only 2.X

For those who wish to convert code from 2.X to 3.X, a tool called 2to3 exists. Fortunately,
a tool that converts the other way—3to2—also exists. Whereas the former is not always
successful, converting from 3.X to 2.X is theoretically easier since the former does not
have too many tough instances that the converter needs to handle. However, it is possible
for code conversion to fail, especially when the source makes heavy use of features
available only in the 3.X branch—such as extended tuple unpacking or function
annotations.

Common code base support for Python 2.X and 3.X

Despite backward incompatibility, there is a fairly large common subset between versions
2.6+ and 3.3+. In Python 3.3, the u prefix support for the Unicode literals has been
restored—this means that semantically correct code written in 2.6+ can now be source-
compatible while still remaining largely “idiomatic”—a concept that will be explained
later on. Handling the different names in versions 2 and 3, however, would mean that
some of the things would not be imported from the same place.

In summary…

Bottom line is that while Python 3.X is more consistent, it lacks the complete support of
third-party modules that 2.X enjoys. This can go on for some time, despite the great efforts
of programmers. And while the 2.X family is effectively at a dead end when it comes to
development, all major frameworks will still run on it. Like in 3.X, this is seen to continue
for a significant amount of time. There’s also a great wealth of documentation already in
place for Python 2.X, while those for 3.X are still cropping up continuously as older
documents are being updated.

Some of all that talk might be confusing for you if you are a beginner to programming.
Hopefully all that will be clear when you finish the book.

But then again, that is the point we are trying to make here—there are subtleties that will
surely differentiate between the two branches of the same language. If you know what
you’re doing, you can make an informed decision on which to use, based on all we have
laid out here. But if you are just starting off, you should stick to whatever you have on
your computer as you read this—there will be time to mull over versions later.

Speaking of starting off, the next chapter should send you on your merry way!

CHAPTER 7: Learning How to Count—Python Integers

In the first chapter, we compared Python to ABC. Here, let us consider how Python does
numbers—123.

There are two types of numbers in Python—integers and floats. Integers (“int”)here follow
the same conventions we have learned in school mathematics . They are whole numbers—
5, 9, -75, 5000 are all examples. Numbers with decimal points—such as 3.1416—are not
integers. Instead, they are floats.

As if the distinction wasn’t easy enough to figure out, Python has a nifty tool to figure out
whether a number is an integer or not. Simply use the built-in “isinstance” function to
check if an item is an integer or nor:

>>> isinstance (54, int)
True

Note that all you have to do is to place the number and the term “int” inside a parenthesis
after the “isinstance” function. The “int” provides the condition “isinstance” will compare
against. If you get a True. Then the number is an integer. A False would mean the number
is a float.

If you fancy something just a wee-bit more challenging, you can exploit the concept of
integers in order to turn the shell into a calculator. Simple mathematical operations can be
performed on integers—addition, subtraction, multiplication, and division (+, -, *, /
respectively). For example:

>>> 10+10/2
15.0

If you have noticed in this line, Python followed the order of operations—multiplication
and division first, then addition and subtraction. This is why the answer did not turn out to
be 10. You will also notice that the output is a float, despite the decimal section being a 0.
In Python, a float always comes out when you try to divide. Lastly, a minus sign in front
of any number inverts its sign into negative.

But what if you want to divide and get a whole number as an answer? This can also be
done through “floor division”. To use this feature, simply use two slashes (“//”) when
typing out the problem. For example:

>>>700//7
100

Floor division works by rounding off the resulting quotient, therefore giving you a whole
number—an integer—all the time.

You may also wish to get just the remainder of a division process by using the modulo
feature. This can be accessed through the percent sign:

>>>1%52
1

For those wanting to solve the power of a number, two asterisks (“**”) can be used:

>>>2**5
32

Non-Decimal Integers

The numerical system that we are accustomed to using—as well as most numeral systems
in the world—is ten-based. While this is a very useful way to go about our daily tasks, this
isn’t often the most useful way of communicating with computers. This is why
programmers commonly employ other forms of numerical systems—binary, hexadecimal,
octal, etc. These numeral systems will have to be partially covered in this section, in order
to gain a deeper understanding of Python’s numbers.

Let’s start with binary. This is something that most people have already heard, and yet is
something that is not all too commonly understood. While it has always been inextricably
linked to computer language, binary as we know it has been in use way before electricity
even came into widespread use. As the word suggests, “binary” is based on the numeral 2.
This means that only two numbers are used—1 and 0. This makes 1+1=10 instead of the
common sense 1+1=2.

In order to use binary notations in Python, you will need to add the code “0B” or “0b” at
the start of the number. For example:

>>>0B11
3

The output line gives you the decimal conversion of the binary notation that was entered.
Of course, you can also do mathematical notations in binary, but the output will always be
in standard decimal.

Octal numbers, on the other hand, are numbers that aren’t in as much use as the binary
system. One of the biggest reasons is that the numeral system has been surpassed by the
hexadecimal in computer use. Back in the time, octal made perfect sense because it can fit
perfectly into three bits. However, it fails to fit into the standard 8-bit style. In case you
ever need to use octals, however, it is a relief to know that Python still supports them.
Octal numbers are made up of digits 0-7. In order to use the system in a line of Python
code, simply add “0O” or “0o” at the beginning. The octal system behaves in just the same
way that binary behaves.

>>>0o100
64

Then, there is the hexadecimal system which has been deeply ingrained in computer
usage. It is especially useful since it can fit into a “nibble” (Yes, it’s an actual measure—4
bits.). Of course, two nibbles make a byte, where hexadecimal still works. The only tricky
part is that hexadecimal has to use 16 characters as “digits”—and we only naturally count
from 0-9. This means we are using 0-9, and adding in A-Fin order to complete a
hexadecimal notation. And yes, we are using letters as numbers.

In order to work with hex numbers in Python, you will need to add the “0X” or “0x”
prefix to the line of code.

>>>0xE
14

Note that you do not have to necessarily use capital letters when working with
hexadecimals—the extra pinky finger movement may prove tiring. If you are more
comfortable, lowercase letters would also work.

This topic of non-decimal integers might not come into play until you are in the
intermediate to advanced stages of Python programming—however, it will be important to
understand how to tap them now that we are in one of the most basic of Python lessons.

Python Floats

Integers may be great for many situations, but the fact that they are whole numbers can
pose quite a limit on them. First of all, they are not necessarily real numbers. In
mathematics, a real number is any value that will represent a quantity along one
continuous line—a definition that puts fractions (in decimal forms) within its folds. This
means that 3.1416 and 1.75 are both real numbers. In the field of computer science, these
numbers are called “floats”. In order to test if a number is a float (despite the easy
distinction), we can do similar tests to what we did for integers.

>>>isintsance (4.5, float)
True

>>>isinstance (0, float)
False

Like before, the word “True” will appear for positive matches with the “float” condition
and a “false” will appear otherwise.

As a rule of thumb in Python, floats are those that have a decimal point while integers are
those that do not. That the two have the exact same value is not considered—as in the case
of 77.0 (float) and 77 (integer). When it comes to the arithmetic operations, the same ones
we saw for integers will be applicable for floats.

Before you start playing with floats on your own, there is one other thing you need to
know—floats are limited to only a certain degree of precision. This is due to Python’s (and
computers’) architecture. Consider for example the following piece of code:

>>> 2+0.00000000000000000000099
2.0

As you see, the answer is still a float—however, the sum cut off all the other decimals and
displayed only 2.0. This is technically fine for simple everyday computing, since the two
9s on the end are basically insignificant numbers.

Check out this other example:

>>>1.13-1.1
0.029999999999999805

This is another demonstration of how floats lose precision. Of course, the answer would
be a simple 0.03. However, quirks of computer memory architecture brought out a
different answer. You will notice, however, that as the minuend (the first number in a
subtraction equation) increases in value, so does the answer regain precision.

Hence, when working with Python, it is important to know that there may be a margin of
error when dealing with decimals.

Booleans

Students of logic will remember this. In Python as in many programming languages, a
Boolean is either a True or False value. This is essentially a special data type, and is
considered a subclass of integers. A Boolean has two distinct states, and only one of those
states may be there at a time. Think about it—there are many different Boolean values that
we work with everyday—hot or cold, on or off, light or dark.

Aside from the True or False of Booleans, there is the Boolean expression—which can
take such a statement such as 1=0 and 1=1 and churn out a valuation of False and True
respectively. Any empty number or data type will be judged as False, and all other will be
judged as True. The “bool()” method can be used to demonstrate this:

>>>bool(“Python”)
True

>>>bool(785)
True

>>>bool(0)
False

>>>bool(“”)
False

>>>bool()
False

>>>bool(0.0000000)
True

Note that both True and False are case-sensitive—this means that you have to type them
exactly as they are shown, otherwise Python will prompt you a syntax error.

Just like in logic, Python’s Boolean statements can also use operators—and, or, not. The
“and” operator produces a True answer if you have all the Booleans as True—otherwise, it
is False. The “or” statement will allow a True answer as long as one (or more) of the
Booleans is True. If all of them are False, then a False answer will be given. Finally, “not”
will reverse the Boolean partnered with it.

To see it in action, here are a few examples:

>>>not True
False

>>>False and False
False

>>>False or True
True

>>> not (True and False)
True

>>>not (False or True)
False

Complex Numbers

In mathematics, complex numbers are represented as a+bi—where both a and b are real
numbers, while the i is an imaginary number (where, in turn, i2=-1). Within the world of
computers—and particularly in Python—the i is denoted as j. This makes the equation
a+bj. One should also note that both a and b are being treated as floats. This will be further
discussed later.

>>>1+5j
(1+5j)

>>>0+2.5j
2.5j

If you will be experimenting with this, note that j is not case sensitive and so you can use
the uppercase letter. You can also try extracting the real and imaginary numbers from the
complex number:

>>>(2+7j).real
2.0

>>>(5+24j).imag
24.0

Note that you will either have to put the entries inside parentheses, or else you will need to
store them inside a variable. If not, then you will start getting weird results.

Number Conversions

Since floats and integers cannot always be mixed together, you will have to be able to
convert one to another. Thankfully, Python provides for a very easy way to do this.

Let’s start off by converting floats to integers, using the “int()” method.

>>>int(7.3)
7

>>>int(False)
0

>>>int(True)
1

You can also convert strings, though this will be discussed in better detail later.

In order to convert integers to floats instead, it’s pretty much the same—use the “float()”
method.

>>>float(452)
452.0

>>>float(False)
0.0

>>>float(True)
1.0

Note that these two previously-mentioned methods cannot be used on complex numbers,
or else Python will throw errors. You can get around this by extracting the real or
imaginary parts of the number, through the “.real” and “.imag” methods.

You can also use a built-in Python method in order to convert data into a complex number
—however, this is a bit trickier since it takes two parameters. The first one is the real
number (required), and the second is an imaginary number. This is then linked by the
“complex()” method.

Here are some examples:

>>>complex(True)
(1+0j)

>>>complex(1,75)
(1+75j)

>>>complex(“8”)
(8+0j)

>>>complex(“25j”)
25j

One thing that the astute reader would notice is that Python provides a code-based
(method-based) way to ascertain, identify, convert, or operate on even the simplest
numbers—case in point is the process of converting an integer into a float. Remember,
however, that the simplest of the operations we have discussed were not meant to be used
as is—they were all meant to play a part in a longer chain of codes that in turn will
comprise a program.

CHAPTER 8: Python Strings

Aside from numbers, strings are some of the simplest data types not only in Python but in
most other programming languages. Strings can be created simply by putting single or
double quotations around things. Here is an example of a string using single quotes:

>>>’Hello world!’
‘Hello world!’

Strings with double quotes do not affect the string, as can be shown in the following
example:

>>>”Hello world!”
‘Hello world!’

There is also a way to perform a “mathematical” operation on strings even though they are
not numbers—for example, you can join two different strings together by using the plus
sign:

>>>”Hello,”+”world!”
‘Hello, world!’

If the strings are not held by variables, you can also concatenate them:

>>>”Hello” “world” “no” “spaces”
‘Helloworldnospaces’

Note that this last example puts spaces in between the literal strings — but this was only
done for demonstrative clarity. In practice, you will not need to put spaces in between
them in order for concatenation to work. The following will work the same:
“Hello””world””no””spaces”.

Now, imagine that you have to type some very long string, which repeats itself. This can
be done by using the asterisk (*).

>>>print(“hello”*3)
Hellohellohello

Escape Characters

There are a few characters which cannot be expressed easily through a string. These are
the “escape characters”, which can be integrated easily within a string through two or
more characters. In the Python language, we can denote escape characters using a
backslash “\” at the start. To start another line in the string, for example, a line feed could
be added:

>>>”Hello world!\n”
‘Hello world!\n’

This is not really impressive, if you look at it this way. However, let’s try using “print()”
on this line:

>>>print(“Hello world!\n”)
Hello world!


You might not have seen something new… but there is that extra line right under the
string, ready to receive a new string.

For your reference, here is a table of the other escape characters. Don’t worry about
memorizing them, though, since the most important one you have to use is \n

\’’ – Double quote
\* – Single quote (‘)
\ – Backslash
\a – ASCII Bell
\b – ASCII Backspace
\f – ASCII Form-feed
\n – ASCII Linefeed
\r – ASCII Carriage Return
\t – ASCII Horizontal Tab
\v – ASCII Vertical Tab
\ooo – A character with the octal value ooo
\xhh – A character with the hex value hh
\N{name} – A character with the name “name” in Unicode database
\uxxx – A character with the 16-bit hex value xxxx.
\uxxxxxxxx – A character with the 32-bit hex value xxxxxxxx

For the astute reader, the usage of the backslash might pose an entry into a problem with
the string. For example, here is a line of code where the programmer needs to print a
directory name for Windows.

>>>print(“C:\newfolder”)
C:
ewfolder

This is an example of where the “\n” escape character kicks in, creating a new line and
picking up with the “ewfolder” part. In order to correct this, one could then use the
“backslash” escape character — “\”. Hence, we have:

>>>print(“C:\newforlder”)
C:\newfolder

This might grow tiresome, however, when you have very long directory strings. This calls
for a simple way than using two backslashes all the time. In this case, we can simply use
the prefix “R”. Like most instances, one can use the lowercase version as well. Once you
place this prefix before your string quotations, Python interprets the string as a literal or
raw one. In fact, “R” stands for “raw string”. This will tell Python to ignore the escape
characters within the entire string. Here is an example:

>>>print(r”C:\newfolder”)
C:\newfolder

You may also assign the strings as variables. Here is how it’s done:

>>>spam=r”C:\newfolder”
>>>print(spam)
C:\newfolder

Newlines

Now, say for example that you want to print text in multiple lines. You can do it this way:

>>>print(“Hi!\nHello!\nHeya!”)

Such a string can turn into a very long (and confusing) line, but there is a trick that you
can use to allow you to span the text into multiple lines. This can be done with three
quotations (“””) in order to start and end the string.

>>>print(“””
…Hi!
…Hello!
…Heya!
…”””)

Hi!
Hello!
Heya!


As you see, this can make things a lot easier and a lot less confusing. However, you will
also notice that there is a linefeed that appears at the very start. This can be improved by
adding a backslash at the start:

>>>print(“””\
…Hi!
…Hello!
…Heya!”””)
Heya!
Hi!
Hello!
Welcome!


As shown, this fixes the issue and puts out the errant linefeed.

Speaking of errant linefeeds, trying these exercises in your Python interpreter would alert
you to the fact that the language automatically places another linefeed on the end of
print(). If you wish to bypass this, it can be done this way:

>>>print(“Welcome to Python!”, end=””)
Welcome to Python!

You can also string multiple lines without having to deal with automatic linefeeds. This
can be done by using parentheses:

>>>spam=(“Hello
…world!”)
>>>print (spam)
Hello world!

Formatting

Much like in the C language, the strings in Python can also be subject to special
formatting. This serves a specific purpose by easing the way for a better-formatted output.
You will be able to format a string using the percent sign (%). You can also use the curly
brackets ({}) formatting. Here is an example:

>>>print(“The number five (%d).” %5)
The number five (5).

The example code used the special format character %d, which has been replaced by a
decimal-based integer. We used the percent sign (%) right after the string—this is the item
that replaces the format characters. Below is another demonstration of formatting strings:

>>>name=”Python”
>>>date=2016
>>>print(“Copyright (c) %s %d” % (name, date))
Copyright (c) Python 2016

Notice the usage of the comma and the parenthesis. If these are not added around the
format arguments, then an error will appear.

Here is a table of all the most commonly used formats in Python:

s. This is a string format, which is the default for formatting.
b. This is the binary format.
c. This converts the integer into a Unicode character, before being formatted.
d. This is the decimal format.
o. This is the octal format.
x. This is the hexadecimal format. Use the lowercase “x” for a-h, and the uppercase “X”
for A-H.
n. This is the number format. This is almost the same as “d”, but this instead uses the
current locale setting in order to insert the needed number separators.
e. This is the exponent notation. This will print the scientific notation of the number. There
is a default precision level (6). You can also use the uppercase version, which will print an
“E” in the notation.
f. This is the fix point. This will display a “fixed-point”number, with the default precision
of 6. You can also use the uppercase version, which will convert “inf” to “INF” and “nan”
to “NAN”.
g. This is the general format. You can also use the uppercase version, which will
automatically switch to “E” once the numbers become too large.

Indexing

The strings in Python will support indexing, which will allow the programmer to retrieve
just a part of the string. The following is a demonstration so that you can easily grasp this
concept:

>>>”Hi there!”[1]
‘i’
>>>spam=”Hi there!”
>>>spam[1]
‘i’

As can be seen in the example, there is a number in the square brackets ([])—this is the
index number. Using this, you will be able to extract a character from the string partnered
with the index number. Remember that in Python, indexing starts from 0—so the
maximum possible index of the specified string is one less than the number of all
characters in it. Punctuation marks and spaces also count as characters. In case you choose
a number that is beyond the string’s length, you will be flashed with a “string index out of
range” error.

Now, consider the following piece of code:

>>>spam=”Hi there!”
>>>spam[len(eggs)-1]
“!”

What you just read is a piece of code that was meant to extract the last character in the
string—no matter how long it is. The formula is the string length (len) minus 1. The
function “len()” is built in, and can be used to automatically count the length of the string.
Typing “len()” will return 9, and 9-1=8—this makes 8 the index number, which then
corresponds to “!”.

The astute reader may see a disconnect here—why did it pull up the “!” instead of “e”, if
we are counting one from the end? This is because the string length count does not start
from zero, although the index number does. Thus, the string has 9 characters in total
(string length), but “!” is indexed as 8 since “H” comes in at 0.

Another important thing to consider is the immutability of strings—meaning their contents
cannot be manipulated. These immutable types have values that are fixed and cannot
change. If you wish to change the value, you will need to reassign the complete variable.
Consider the following example:

>>>spam=”Hi”
>>>spam=spam+” there!”
>>>spam
‘Hi there!’

This piece of code demonstrates how the variable “spam” is assigned to a different value.
How is this then related to indexing? The same rules will apply to indexing—all indexes
cannot be manipulated nor can they be assigned new values.

In order to reassign string variables while replacing a part of the substring, one will have
to work a bit more in slicing the string. This will be taught in the next section, but we will
give you an example of how it looks like here:

>>>spam=”Hi there!”
>>>spam=spam[:2]+”x”+spam[3:]
>>>spam
‘Hi txhere!’

Slicing

In Python, slicing will be one of the more important concepts that you will be learning.
This is a feature that will allow you to extract a “substring” from the main string. This
substring is in essence a string within the string—so the words “Hi” and “there” are both
substrings of the string “Hi there!”. But substrings do not have any boundaries, so you can
extract a single character (letter, punctuation mark, or space) out of a very long string of
text if you so wish.

In slicing, the most important character is the colon (:). Here is an example of the basic
application of the colon:

>>>spam=”Hi there!”
>>>spam[0:1]
‘H’

In this example, you will see how Python builds upon the indexing feature that we had
previously discussed. The line “spam[0:1]” uses the slicing feature on the string encased
in the spam variable. It is basically read by Python as “get the substring starting from the
character with the index 0 until the character with the index of 1”. In essence, the first
number spells where the slice will begin, and the second number is where it will end.

This form of slicing can be helpful in many situations. However, what if you wish to get
just the first 4 characters after the start of the string? The len() function can be useful, but
there is an easier method. By removing one of the parameters in our slice function, the
language will slice from either the beginning or the end (depending on which side of the
colon was omitted).

Here is an example:

>>>eggs=”Hi there!”
>>>eggs[:6]
‘Hi ther”
>>>eggs[6:]
‘e!’

As was demonstrated, omitting the first number will start counting from the very top all
the way to the specified index number; those after it will be sliced. On the other hand,
removing the number after the colon will start slicing from the start of the string all the
way to the specified number. Another way to look at it is in terms of subsets—when
combined, eggs[:6] and eggs[6:] equate to simply eggs.

You will also notice that in slicing, the common “index out of range” error message does
not apply, even when the index numbers you specify are really out of range. This error is
suppressed, and instead returns the entire string.

Encoding

Now that we know what a string means and how it works (and is worked), it is time to
delve further into its nature. In fact, we have only seen one part of the string’s nature. The
true nature of a string may be different things, without the string having to change—it all
depends on the encoding.

There are two prominent encoding schemes used for strings—Unicode and ASCII. Of the
two, ASCII is the simpler one. It is a simple scheme for some (though not all) Latin
characters, and some other things like numbers, money units, and signs. Unicode, on the
other hand, is a larger encoding scheme that can include up to thousands of characters.
Unicode is used to create one scheme which contains all of the alphabets, scripts, and
characters in the world. Python 3.X uses Unicode as its default encoding system. This
means that one can put almost anything into the string, and it can be correctly printed out
by the interpreter. This is perfect for countries that do not use English as their standard
language. ASCII will do them little good, since it does not allow too much characters—
only 127 are present in this encoding scheme.

CHAPTER 9: Python Lists

In Python, a list is an important data type which allows the user to keep sets of iterable
items. A list is a mutable sequence—meaning that you can have a long list of items. You
can denote a list using square brackets ([]). For the list to hold actual items, you have to
place them within the brackets separated by commas.

Here are a few examples of a list:

>>>[78,92,56,1491]
[78,92,56,1491]

>>>[“h”,”i”,”t”,”h”,”e”,”r”,”e”,”!”]
[‘h’,i’,’t’,’h’,’e’,’r’,’e’,’!’]

You can also convert a non-list into a list, using the built-in Python function “list()”. This
will be further discussed later on, but this is how it looks like:

>>>list[“Python”]
[‘P’,’y’,’t’,’h’,’o’,’n’]

A list is also capable of holding different data types, so a programmer can safely mix
strings, numbers, and even complexes. You can also nest lists within lists:

>>>[[5,4,7,6],[“a”,”x”,”o”].[True, True, False]]
[[5,4,7,6],[‘a’,’x’,’o’].[True, True, False]]

Obviously, nesting can get pretty complicated as the nests go deeper and deeper. However,
it can be leveraged into a powerful tool that will be harnessed at a later segment in this
course.

List Indexing

Just like how strings can be indexed, so can lists. Indexing can then be used to get a
specific item from the list. For example, if you wish to have the letter “o” extracted from
[‘P’,’y’,’t’,’h’,’o’,’n’], you will have to types [‘P’,’y’,’t’,’h’,’o’,’n’][4]. For brevity,
though, the list can be placed within a variable first. And again, do not forget that indexing
always starts at zero, even in indexes.

Just like strings, one can index starting from the last item using negative numbers. Note as
well that a -0 does not exist, and is just interpreted as 0. You should instead use -1 if you
want to start counting from the end. And of course, if you try to index with a number that
is out of range, then an index error will return.

List Slicing

And like strings, lists can also be sliced. When slicing a list, it will return with a newly
sliced copy of the main list—meaning, the answer will also be a list.

List Manipulation

Manipulating lists is also quite basic. The best way to add a new item to a list is to use the
built-in Python function “append()”. This can be done easily, as shown below:

>>>spam=[5,4,3,2,1]
>>>spam.append(7)
>>>spam
[5,4,3,2,1,7]

Unlike strings, however, lists can be changed—they are mutable. The best way that this
can be done is through indexing. Below is a demonstration:

>>>spam=[1,2,3]
>>>spam[0]=50
>>>spam
[50,2,3]

As you see, we were able to change the first value in the list.

As far as removing items from lists go, there are a few ways for this to be achieved.
However, because the 13th Zen so dictates, there should be a path of least resistance that
should be most preferable. This is demonstrated below:

>>>toast=[1,2,3]
>>>del toast[1]
>>>toast
[1,3]

As you noticed, the simplest way is simply to append the “del()” function to the index
number of the item that you wish to delete. Note as well that when an item is deleted, the
remaining items move to the left (when applicable). If you keep on deleting the item “0”,
then the entire list will be deleted soon enough. Instead of this, however, the most efficient
way to delete an entire list is as follows:

>>>toast=[1,2,3]
>>>del toast[:]

This kind of function totally removes all the items from the list. Note that this example
only deletes the list, however—the variable is still there. If you wanted to delete the
variable itself, you should use “del dog”. This will be further explained in a later chapter.

As previously mentioned, the list is a mutable type—this means that content may change
dynamically. Take, for example, the hypothetical list “spam”. This is not the list, but a
variable that points to the location of the list. Another real-world example is an address
book—it points to the location of the house, but not the house itself. Also, it does not
know what is in the house. The list “spam” has the same traits.

This leads us to some questions—foremost is, how would one copy the list “spam” if it
only has the address of the list? Since the variable contains the address, giving a different
variable this same address will not help. Consider the following:

>>>spam=[1,2,3]
>>>toast=spam
>>>spam
[1,2,3]
>>>toast
[1,2,3]
>>>spam[1]=5
>>>spam
[1,5,3]
>>>toast
[1,5,3]

As we saw from this example, the variables “spam” and “toast” both point to exactly the
same list—any change that will point to any of these variables will change the other one as
well. This is like having two separate addresses point to the same house. In Python, this is
called “shallow copy”. For those who want to have two completely different lists (think of
two identical but physically different houses, on separate addresses), you will need to do
what is called a “deep copy”. The language always creates a deep copy for slice
operations, so a simple slice can create a new list for “toast”:

>>>spam=[1,2,3]
>>>toast=spam[:]
>>>spam
[1,2,3]
>>>toast
[1,2,3]
>>>spam[1]=5
>>>spam
[1,5,3]
>>>toast
[1,2,3]

Remember this, because it is a very important concept. It can save you lots of headaches
in the more advance sections.

Built-in Functions

This section will tackle the different list functions built into Python.

.append() – This adds an item to the end of the list.

>>>spam=[1,2,3]
>>>spam.append(5)
>>>spam
[1,2,3,5]

.clear() – This removes all of the items from the list
.count() – This returns the number of times that a given item appears in the list.

>>>spam=[1,2,3,5,5,1,5,4]
>>>spam.count(5)
3
>>>spam.count[1]
2

.index() – This will find the index of any given item within the list. There are two optional
parameters for the start and end of the index.

>>>spam=[1,2,3,5,5,1,5,4]
>>>spam.index(5)
3
>>>spam.index(1)
0
>>>spam.index(5,1)
4
>>>spam.index(1,2)
5

.extend() – This appends a list at the end of the list.

>>>eggs=[1,2,3]
>>>eggs.extend=[1,2,9]
>>>eggs
[1,2,3,1,2,9]

.insert() – This inserts an item into a certain index position. Again, remember that
Python’s indexing begins at zero.

>>>bacon=[1,2,3,4,5]
>>>bacon.insert(2,”jam”)
>>>bacon
[1,2,’jam’,3,4,5]

.pop() – This will return the content of a specific index, after which it is deleted.

>>>spam=[1,2,3,4,5]
>>>eggs=spam.pop(2)
>>>eggs
3
>>>spam
[1,2,4,5]

.remove() – Just like .pop(), except that it does not return the item before deleting it. This
makes this function slightly faster than .pop().

>>>jam=[1,2,3,4,5]
>>>jam.remove(2)
>>>jam
[1,2,4,5]

.reverse() – This will reverse the list’s order.
>>>juice=[1,2,3]
>>>juice.reverse()
>>>juice
[3,2,1]

Lists are very useful assets, and they offer a lot of flexibility. However, remember that
there are other alternatives—such as tuples, which are four to seven times faster and are a
lot more static than lists). Because of lists’ inherent characteristics, very long lists can
usually incur a penalty in the program’s performance. This is why most lists are best kept
short. In Python’s rule of thumb, lists are best used by those who wish to dynamically hold
values and information.

CHAPTER 10: Tuples

Towards the end of the previous chapter, we learned that there is a Python data type that
can be much faster than lists, though not quite as flexible. These are tuples, which are
immutable sequences. In nature, lists and tuples are very similar—except that you will not
be able to dynamically modify the tuple in the same way that you do lists.

Once a tuple is created, it can no longer be modified or changed. The way that this affects
how the tuple is stored in the memory will be an important idea later on. In order to create
a tuple, the programmer will create a group of items that are separated by a comma (,).
While Python adds parentheses around any item group, it will not be as important, since
the result will still be a tuple. This is demonstrated below:

>>>spam=1,2,3
>>>spam
(1,2,3)
>>>”Q”,”W”,”E”,”R”
>>>(‘Q,’W’,’E’,’R’)

Now, here is a little riddle: what if you only want one item to be stored in your tuple? This
can simply be done by leaving an extra comma at the end. In fact, you can choose to leave
an excess comma after any tuple, regardless of its size (even though this is not explicitly
required for any tuple larger than one). This is one of those little quirks unique to the
Python language.

Note as well that you can make an empty tuple simply through an empty pair of
parentheses.

Indexing Tuples

Just like lists and strings, tuples follow the standard indexing rules. Staring from the left,
indexing begins counting from 0; from the end, it counts from -1. Extend slicing is also
supported. You can review this from the previous chapter, since this can be quite tricky.

Built-in Functions

Like in lists, there are also some built-in functions for tuples. There are only two of them,
though, owing to the relative inflexibility of tuples.

.count() – This returns the number of times that a specific item is found. It also works in
the same way as .count() for lists.
.index() – This locates the first index of the specified item. It also works like .index() for
lists.

Using Tuples

Just like lists, tuples were made for a specific type of usage. They are perfect for holding
data you want to be static, and that you don’t plan or changing or modifying. Just like
what is said in the previous lesson, a tuple is up to seven times faster than lists. This
means that for each item in a list that is manipulated, four to seven tuples could have been
manipulated in the same time frame. This generates a huge advantage in speed, especially
for scientific work.

Though this sounds very good, remember that once a tuple is created it can no longer be
changed. The best metaphor for this is that tuples are “read-only”. In order to change the
content, tuples have to be changed into dynamic an mutable sequences. Only after
manipulation are they converted back into tuples. For this same reason, those intending to
add and remove items in sequences should not use tuples.

CHAPTER 11: IF Statement

Earlier, we had mentioned in passing about the special place indentation has in the Python
language. Unlike other languages such as Java and C++, Python uses the indent to
determine a block of code. This pseudocode demonstrates this:

This is a line of code.
This is another line of code
This code, on the other hand, is part of a code block.
This is also a part of a code block.
Unfortunately, this code is no longer part of a code block.
But this code is the start of a new code block.

As was seen from the pseudocode, there are multiple areas that form blocks of codes. You
can even nest a block of code within another block, as long as it indents. There is
technically no limit in indentation, but the programmer has to mind the indentation’s
consistency, or else, an error will be generated. Consider this next batch of pseudocode:

This is a line of code.
This line is part of a code block, which is pretty far away.
While not encouraged, this indentation is legal in Python.
For consistency, indenting in multiples of four are preferred.
This line is no longer a part of a code block, since it does not follow
any indentation style.
This would get you an error.

While the programmer is allowed to use both white spaces and tabs, it is preferable to use
white spaces. Be reminded that you will not be able to use both tabs and whitespaces at
the same time, or an error may appear.

One should know that since the Python interpreter is used in demonstrating the example
code, an ellipsis (…) is virtually same as three greater-than signs (>>>). The only
difference is that an ellipsis means you are in a code block. The following demonstrates
this:

>>>if True:
… Print(“Hi there!”)

Hi there!

Some programmers may be more comfortable in using curly braces ({}) to determine code
blocks and statements, especially those who are just starting Python after learning a
different languages. These brackets (also called braces) are some of the most debated-on
signs in Python. As of this writing, the core Python developers are continuing to reject the
use of braces due to the Python Philosophy. In fact, if you try to opening up the Python
interpreter and typing “from_future_import braces”, you will get a little easter egg that
will sum up the collective attitude of Python’s core developers (towards braces, at least)
—SyntaxError not a chance.

Now that this has been gotten out of the way, we can get into the nitty-gritty of the lesson.

The If Statement and Code Flow

In a majority of programming languages, there are special ways of controlling the code
“flow”. Such a control allows specific parts of the code to execute only when the
conditions are right. Among the different codes used towards this end, the most commonly
used is the if statement. This is meant to first compute whether a statement is true or false
—if the statement is true, the code is executed; if it is false, the code is not.

Remember that the True and False expressions are Booleans in the Python language. This
means that the if statement (as well as other conditional statements) will be using Boolean
math in order to compute the evaluation. One should also note the proper way a
conditional statement is written—a colon (:) at the end is necessary at the end of “control
flow” statements.

Here is an example:

>>>if 1==1:
… Print(“This is gonna print!)

This is gonna print!
>>>if 1==2:
… Print(“This won’t ever print.”)


You can also use what was previously discussed about Booleans (and, or, not) in order to
mix different conditions together.

>>>if 1==1 and 3 ==3:
… Print(“True”)

True
>>>if 1==2 or 3==3:
… Print(“True”)

>>>if 1==2 or 3==4
… Print(“True”)

>>>if not False:
… Print(“True”)

True

As was previously mentioned, you can nest statements within statements so long as the
respective indentations are followed.

>>>if 50==50:
… Print(“50 equals 50”)
… If True:
… Print(“True is True”)

50 equals 50
True is True

While statements can always be nested within each other, it can quickly become hard to
manage. It would have been more Pythonic if the statements are kept flat. This would
mean that instead of nesting different if statements together, it would be better to use a
single if statement with different and operators.

>>>if 2==2:
… If 4==4:
… If 6==6:
… Print(“2,4, and 6 are equal)

2,4, and 6 are equal
>>>if 2==2 and 4==4 and 6==6:
… Print(2,4, and 6 are equal)

2,4, and 6 are equal

If you found the line being printed to be queer, remember the basic rules in school logic—
operators do not care about the final line being true or not in the real-world, so long as the
prerequisite conditions are met.

Backslashes, Semi-colons, and Parentheses

Most likely, you will want to keep several different lines of code in just a single line. This
can be done using the semi-colon (;). This acts like a new line, except that the programmer
will not see it in this way. Take, for example, the following lines of code:

>>>if 1 !=3:
… a=1
… b=2
… c=3


The same code may be condensed into a single line, just like shown here:

>>>if 1 !=3: a=1;b=2;c=3


The good thing about semi-colons is that they do not need to indent. This takes away the
need to carefully count the number of times you have indented. While this is a great thing,
remember that semi-colons should not be used excessively. This is just to make sure that
you are not writing a large chunk of code all just on one line as that would be more
confusing to manage. Take a look at this bad example:

>>if 1 !=3 a=1;b=2;c=3;d=4;e=5;f=6;g=7;h=8;i=9;j=10;


Now, let’s tackle another dilemma. Let’s say that you would need to compare six different
numbers using an if statement. This statement would become quite long, and nesting them
in different statements would make things worse. This can be solved by using a backslash
(\). This allows you to break up a long line of code into different parts.

>>>if 2==2 and 4==4 and 6==6 and 8==8 and \
… 10==10 and 12==12 and 14==14
… Print(“True”)

True

Just like in the case of the semi-colon, the programmer will not need to worry about
indentations when dealing with the backslash. This will allow you to keep the code in
level with the if statement. However, remember that any character appearing directly after
the backslash will cause an error to appear. This extends all the way out to excess
whitespaces that may have been mistakenly typed. Remember to be extra-careful when
dealing with backslashes.

Then again, there is an even more workable solution—using parentheses to include all of
the pertinent code. This works just like the backslash, however it allows for extra
characters (including whitespaces) appearing at the end.

>>>if (2==2 and 4==4 and 6==6 and 8==8 and
… 10==10 and 12==12)
… Print(“True”)

True

Note that for some Pythoneers, it is considered “unpythonic” to use parentheses instead of
backslashes. This is, however, not 100% accurate all the time.

The Else Statement

There would be a lot of times when you wish to execute a different line of code in case the
if statement is not true. This would call in the use of the else statement. The statement
accompanying this will be executed when the preceding statement is false. To work, it
needs to be on the same level of indentation as the if statement. Here is an example:

>>>if 3==3:
… Print(“3 equals 3”
… Else:
… Print(“3 is not equal to 3”)

3 equals 3
>>>if 3=33:
… Print(“3 equals 33”)
…else:
… Print(“3 is not equal to 33”)

3 is not equal to 33

While both if and else have to be aligned to each other to work, the indentations of their
code blocks can be different as demonstrated by the following example:

>>>if 2==2:
… Print(“2 equals 2”)
…else:
… Print(“2 is not equal to 2”)

2 equals 2

While there is no requirement for it, it is again recommended that you indent in multiples
of four.

The Elif Statement

As you might have noticed by now, the Python language often provides shortcuts (or at
least some kind of reprieve) in case one has to do tedious tasks. For example, the
programmer wants to have four if statements together—but you only need one of these to
execute. The programmer can always try to write all those four statements, but then again
it would be a lot easier to just write one big chunk directly using the elif statement. The
term elif stands for “else if”, that acts like both the else and if statements. This would mean
that if the first if is not true, the elif will kick in to see if it is true. This can be avery handy
feature later on. Check out the following blocks of code:

>>>if fraction == 1:
… Print(“The fraction is a whole”)
…Elif fraction == 3/4:
… Print(“The fraction is 3/4”)
…elif fraction == 2/4:
… Print (:The fraction is a half”)
…elif fraction == == 1/4:
… Print(“The fraction is 1/4”)
…else:
… Print(“The fraction is none of the above”)


CHAPTER 12: While Statement

While the if statement we learned in the previous lesson can be applied for different
purposes, it does not do quite as well a job at being recursive. This means that this
statement is not made to loop multiple times. At this point, the while statement comes into
play. This statement will work for as long as it needs to, until the conditions are proven
false. This is useful in case something has to be repeated multiple times for a specific
amount of time. Below is an example that demonstrates this:

>>>spam= 0
>> >while spam !=5:
… Spam +=1
… Print (spam)

1
2
3
4
5
>>>bacon=[2,4,5,6,8]
>>>while bacon:
… Print(bacon [0])
… Del bacon[0]

2
4
6
8
>>>while False:
… Print(“This will not print”)

>>> juice=10
>>>while juice:
… juice-=1
… print(juice)

9
8
7
6
5
4
3
2
1
0

The condition of the while statement will always be true or false, just like the if statement.
This will mean that Booleans can also be used to force the looping. In the same vein, while
False: will not execute—in the opposite end, while True: will loop infinitely. This will be
important in more advanced lessons.

The Else Statement

In Python, unlike in many other languages, the else statement can be legally used in
conjunction with the while statement. When the while finishes the loop naturally, the else
statement will kick in. If the while statement is prematurely stopped, then the else
statement will not execute. Below is an example:

>>>jam=0
>>>while jam !=10:
… jam+=1
… Print(jam)
…else:
… Print(“Finished printing jam”)

1
2
3
4
5
6
7
8
9
10
Finished printing jam
>>>while True:
… Pass
…else:
… Print(“This will not be seen on the screen”)

Traceback (most recent call last):
File “<stdin>”, line 2, in <module>
KeyboardInterrupt

In the second batch of code, the KeyboardInterrupt was generated by a ctrl+c, Like
mentioned earlier, the while statement was prematurely stopped and hence the else was not
executed.

The Break Statement

Sometimes, the programmer may wish to intentionally end a while statement prematurely.
This is done through the break statement. This statement is nested in the while statement
that it will end. This means that only one while statement will be ended, and not all of
them. Below is an example:

>>>spam=0
>>>while True:
… Print(spam)
… Spam +=1
… If spam ==10:
… Break

0
1
2
3
4
5
6
7
8
9

This example shows how a while loop is ended, even while it is true. You will also notice
that the break statement we demonstrated did not need a colon. This means a new
indentation is not needed. Placing the colon will cause an error—meaning this omission is
mandatory.

Continue Statement

Just as the break statement can be useful, so can the continue statement. Unlike the
previous statement, continue will stop the current code execution and proceed to the
beginning of the while statement. This is used to skip a part of your code without ending
the loop. This statement is used just like the break statement. Here is an example:

>>>eggs=0
>>>while eggs!=10:
… eggs+=1
… If eggs <5:
… Continue
… Print (eggs)

5
6
7
8
9
10

Astute readers will notice that the example above could have been complete even without
the continue statement. It does, however, demonstrate exactly how the statement works. It
is used to reduce the need for indenting and nesting. It would be a bit easier to check the
five conditions and use continue when they fail. This is in comparison to nesting five if
statements. This can also reduce the time needed for typing, also directly affecting the
clarity and readability of the code.

CHAPTER 13: For Statement

Earlier, we demonstrated how important the while statement is for recursive loops.
However, we had not covered its weakness—that of its use in iterator-based recursions. In
computing, “iterator” is a term used to describe a method capable of doing the same action
for every item in a given collection.

When talking about iterator-based recursions, the for statement takes center stage. This is
used to loop based on a collection. It puts each of the items within into a temporary
variable, made immediately available for use. For “syntactic sugar” (i.e., that part of the
code that makes it easier for us humans to read and write it), the in statement should also
be used. This is demonstrated in the following:

>>>for bacon (“A”, “B”, “C”, “D”, “…”):
… Print(bacon)

A
B
C
D


As can be seen here, the temporary variable which has the item from a collection or
sequence follows the for statement. In this instance, bacon is our temporary variable. After
this, the in statement is needed, preceding the collection or sequence.

The way that the for statement is used in C-based languages and Python can differ
significantly. Since the version used by Python is iterator-based, it comes as a question
how the programmer would have a temporary variable hold a specific number which
increments on each loop. One solution would have been to make a large tuple to hold
every number, but this would unnecessarily take up both time and memory. The built-in
range() function is a good tool that can help us in this little puzzle. The range() function
can create an iterator list of the numbers, without the need to waste both keystrokes and
memory. This is an example of the range() usage:

>>>for juice in range (10):
… Print(juice)

0
1
2
3
4
5
6
7
8
9
>>> for jam in range (2,10):
… Print(jam)

2
3
4
5
6
7
8
9

All things considered, the range() function can be quite complicated. This is why the
above example show it in its two most basic forms. When only a single parameter is used,
then the new range starts from 0 and ends at the parameter. In the case of range(10), the
range is computed from 0 to 9.

The next example makes use of two parameters. The first one signifies the start of the
range, instead of the previous default (0). Like before, the second parameter is where the
numbers should stop. In the example, the range(2,10) counts from 2 to 9.

While the range() function begets an iterator list, it is not by itself an iterator. The function
is in reality called a “generator”. This is any object that can create a group of iterators
when needed. Since it is the generator that works, the iterators are temporary—they are
not meant to stay forever in the computer.

The Else Statement

Just like the while statement, the else statement of the for is executed when the loop does
not prematurely end (for any reason). Any special keyboard keys, errors, and other
statements (among others) would render the statement inert. Here is a short example:

>>>for eggs in (1,2,3,4,5,6):
… Print(egg%2)
… else:
… Print(“This for loop is successful”)

1
0
1
0
1
0
This for loop is successful

The Break Statement

This statement works for the for statement in much the same way that it works for the
while statement. It completely ends the loop in a premature manner, which can be useful
in some cases. Here is another demonstration:

>>>for jam in (1,2,3,4,5,6,7,8,9):
… Print(jam%4)
… If jam %5 ==0:
… Break
… Else:
… Print(“This loop did not end prematurely”)

1
2
3
0

The Continue Statement

This statement works in just the same way that it does when in the while statement. It is
meant to stop the code’s execution, bringing everything back to the beginning of the loop.
Here is another example:

>>>for spam in (1,2,3,4,5,6,7,8,9):
… if spam%2 == 0:
… Continue
… Print (spam%2)

1
1
1
1
1

Just as mentioned in the previous chapter, the continue statement is also used as a means
to increase the code’s readability and to reduce unwieldy amounts of indentation.

CHAPTER 14: Try Statement

In the perfect programming world, nothing would go wrong. Unfortunately, even the best
programmers make mistakes—that’s why debugging and troubleshooting has become a
core part of the development process. Aside from manual mistakes, computers may go
wonky—crashing, resetting, and shorting out in perfect manifestation of Murphy’s Law. In
the even something goes south, the computer will have to act in a flash and recognize that
something is going on. At this stage, the computer should also stop and try to fix the
problem when it could. Any well-coded software should have at least the basic safeguards
in place for such events.

In programming, an error is produced when the computer has detected something is off.
Take, for example, when you are burning a CD. When you pull out the CD without
waiting for it to complete, then the CD will be unavailable to the software you are using. If
the software is not equipped to handle this kind of behavior then the computer will throw
an “undefined” message. Or, the program could just hang as it tries to burn something
onto a non-existent media. These types of behavior aren’t too useful for the user, so one
should create a way to handle them. Fortunately, in Python, the programmer can write
codes that handle exceptions and errors. This is in contrast to many other programming
languages.

Errors—Python vs C

As you might have noticed when you mistype things in the Python interpreter, the
language’s errors are very “loud”. This means that when something is not right, Python
will ensure that you know about it in the surest way. Others may balk at having every
single mistype scrutinized by an unforgiving system, but as you go on this actually
becomes a necessity.

Let’s take a step back and look at one of Python’s forebears, the C language. It did not
have the built-in error handling that Python now has. Sometimes, the errors just slip by
unnoticed by anyone. This is actually good, since that means the error is “tolerable”.
However, there are some times when the error causes the computer to crash outright—
these are dangerous in many aspects. Because the language does not allow for error
handling, the programmer will have to create their own. This still does not make it easy to
catch all the errors in their tracks.

This is why Python was built with such a sharp eye for errors. Once the language fulfills
its goal of notifying you, you have the buck and the control of what else to do from
thereon. If you do not make any specific call for Python, a default message is then
displayed which is follows by the program’s termination.

Loud Errors

Now that we understand the Python errors in a better light, it is clear that handling these
errors become just as important as displaying them. Let’s say that you create a large
program, which crashes each time you use it. Finding and fixing the issue will become
very important. Python’s loud errors will let you know not just what the error is, but what
caused it too. This allows for faster development due to the faster fixing of errors.

The Try and Except Statement

As far as error-handling goes, we can use the try and except statements. Their usage is
shown in the following (minimal) example:

>>>try:
… Print(eggs)
… Except:
… Print(“eggs has not been defined”)

Eggs has not been defined

As you noticed, id a piece of code that has the try statement causes an error, then the code
execution will stop. From there, it will jump to the except statement. The code in the
except will then be executed, and a different error will appear when the except statement
causes another conflict:

During handling of the above exception, another exception occured.

This is why it is important to mind the except, since you would not want to put another
error-causing code there.

You might also have found from prior experience, that the third line of the error message
will be the one that specified what kind of error happened. In the earlier example, a
NameError has occurred. This is the type of issue that erupts when the name of a variable
cannot be found. This is commonly because the variable does not exist in the first place.
Since the errors can be quite specific, there has to be a set of different exception names—
and there really are! The language has at least 20 well-defined and built-in exceptions to
address each kind of known problem.

So what will happen if the programmer tries to catch the NameError (or any other specific
error for that matter)? In order to do this, one would have the specific error after the except
statement as demonstrated in the following example:

>>>try:
… Print(jam)
… Except NameError:
… Print(“Jam is not defined”)
… Except:
… Print(“An unidentified error appeared”)

Jam is not defined

As we can see, the except statement acts by itself as the default error handler. It can handle
any error that has not been captured by another except statement. This will mean that you
can use a multitude of except statements used to catch errors.

The Else Statement

Again, we can use the else statement in this regard. Just like how it works with the for and
while statements, it will execute when the try statement terminates without any premature
endings or errors. The statement should also come after the set of except statements, such
as demonstrated in the example below:

>>>try:
… Eggs=6
… Print(“I have %d baskets of eggs” %eggs)
… Except:
… Print(“An error has occurred”)
… Else:
… Print(“Everything is fine”)

I have 6 baskets of eggs
Everything is fine

The Finally Statement

This statement is technically similar to the previously-tackled else statement, except that
the finally will always execute when the try statement has failed or when it has
prematurely failed. This statement should go after the else statement, such as is shown
below:

>>>try:
… Print(“spam”)
… Except:
… Print(“There is an error”)
… Else:
… Print(“Everything is fine”)
… Finally:
… Print(“Wrapping up”)

Spam
Everything is fine
Wrapping up
>>>try:
… Print(“juice”)
… Except:
… Print(“There is an error”)
… Finally:
… Print(“Wrapping up”)

Juice
Wrapping up

CHAPTER 15: With Statement

Just like the try statement, the with statement is meant for error handling. This statement is
used to automatically clean up objects. This is helpful in reducing the amount of code that
one has to write. It also allows for the omission of the finally statement as well as the
manually written cleanup of the object.

In using the with statement, one will need to point to the object that one wishes to use.
This is followed by the as statement, which will end with the object’s variable name. The
code below is an example that uses this statement, assuming that “Hello world!” is a line
that appears in the file “hello.txt|”.

With open (“hello.txt”, “r”) as file:
Print(file.read())
Hello world!

Here is another example that uses the except, try, and finally statements. Once more, it
assumes that the sentence “Hello world!” appears in the “hello.txt” file.

try;
File=open(“hello,txt”, “r”)
Print(file.read())
except IOError:
Print(“An I/O error just occurred”)
except:
Print(“An unknown error just occurred”)
finally:
file.close()
Hello world!

However, if there is an error while the file is still open, in this case it will not close. In
other circumstances, one would have to write using a try…finally block to make sure that
there is a proper object cleanup. However, this would need quite a lot of additional work
while sacrificing readability at the same time.

CHAPTER 16: Other Statements

This chapter is meant to cover some of the other statements in Python that haven’t been
covered in complete detail yet.

Assert Statement

This statement is used mostly for debugging. It works by checking a specific condition—if
the condition fails, then the statement will prompt an error. This is used to test a set of
conditions before there is an actual execution of the program. This may be used, for
example, to make sure that a specific variable spam is not zero in number. Below is a
demonstration:

>>>try:
… Spam=0
… Assert spam ==0
… Spam=0/spam
… Except:
… Print(“spam may be zero”
… Else:
… Print(“spam is not zero”)

spam may be zero

In Statement

This might be familiar, as we last saw in when we worked with for statements. While the
in statement was used exclusively in conjunction with for in that lesson, it can also be used
as a standalone statement. Its primary purpose is to check if something can be found in a
particular sequence. The statement then returns a Boolean value to verify (or deny) the
existence of the item.

Here is an example of the in statement in action:

>>>”and” in (“or”, “nor”, “in”, “at”, “and”, “;”)
True
>>>”apple” in “(“orange”, “pomelo”, “watermelon”, “kiwi”, “dragon fruit”)
False

While the in statement can be used on iterators, we can also use it on plain strings since
they are also sequences. When using it on strings, the statement will check if the specified
item is a substring of the specified string. This will mean that you can check if something
is found in something else (e.g., a word within a word). Here is an example:

>>>”x” in “exasperate”
True
>>>”juice” in “jam”
False

Also, do not forget that using the in statement is one of the fastest ways of comparing two
variables.

Is Statement

This statement is primarily used to check if the two specified variables are unique. This
would mean that bot the variables are not the same, or that they do not point to the same
set of values. Unlike the “==” notation used for comparing equality, the is statement is
used for comparing identity. Below is a demonstration:

>>>spam=”bread”
>>>eggs=”butter”
>>>spam is eggs
False

In this example, the programmer created two variables—spam and eggs. They have been
assigned to different strings. Because these are not the same strings, their variables are
likewise different. Now, let us try creating two variables with the exact same text in the
strings:

>>>spam=”coffee”
>>>eggs=”coffee”
>>>spam is eggs
False

Why false? It’s because the two are still not the same. Although both of them have the
same text in the strings, each of the strings are uniquely created and placed in the
computer’s memory. The only way to create two exact same valuables will be to have one
of them point to the other. Thus:

>>>spam = “Hi”
>>>eggs=spam
>>>spam is eggs
True

Pass Statement

This statement is used primarily as syntactic sugar, while also serving as a “nop”—an
instruction that does nothing (contraction of no-op). Plainly put, the pass statement does
nothing. This does not mean it is useless, however, as it serves to leave a code block
empty:

>>>if True
… Pass

>>>for spam in range(15):
… Pass


CHAPTER 17: Functions

In the Python language, a function is a way to reuse a code block so that it is usable more
than once. These functions can give the programmer the ability to minimize the
redundancy of his code. It can also help steer away from wasting several hours at
unnecessary work. Functions let codes have a centralized structure, where a single change
in the function will affect all the other parts that depend upon it. They can also be used to
split up tasks that would otherwise be very strenuous to accomplish.

Creating functions

In order to create a function, it should be defined with the def keyword. This is then
followed by the name of the function, along with a blank pair of parentheses. As before,
this is punctuated by a colon. A function can be part of a code block, so you will have to
indent codes that are within the function. If you fail to follow indentation, you will get an
“IndentationError”.

Here is an example:

Def hi():
Print(“Hello there!”)

This code serves to assign and then create the “hi” function. It would act just like the x=1
command — in both instances, a new variable is created (hi and x).

Now that a function is created, you might be waiting for something to change—but
nothing will happen yet. In order to call or invoke the function, the programmer will need
to use the name of the function followed by the parentheses. This is demonstrated in the
following lines of code:

Def hi():
Print(“Hello there!”)

Hello()

This should produce the following output:

Hello there!

Adding another instance of the command will result in the output coming out twice. This
is just a small part of the usefulness of the function.

Parameters of Functions

Perhaps you might be wondering what is the use of the blank parentheses when calling out
functions. True, typing “hello” would be two keystrokes (three, if you count Shift) shorter
than “hello()”. However, these parentheses serve as the “conduit” for passing arguments to
the function. This will allow the programmer to create a function that can do things that
are passed onto their arguments. First off, the argument has to be declared when the
function is initially defined. And then, this is called with an argument.

Def spam(x):
Print(x**2)
Spam(2)
Spam(3)
Spam(4)

The output of these lines should be:

4
9
16

The variable x acts within the spam function. You should notice that x will only exist if it
is within the function. Let’s take a look at these lines of code:

Def eggs(x):
Print(x**2)

Eggs(2)
Eggs(3)
Eggs(4)
Print(x)

This will return a NameError since the variable x cannot exist by itself, outside the square.

Functions are able to take up multiple arguments, separated by commas. This is
demonstrated below:

Def juice(x,y):
Print((x**2)+y)
Juice(2,3)
Juice(3,2)

Notice that this may be a great tool for those studying algebra (or related subjects). The
result should be:

7
11

Default Parameters

Parameters are great, but they can also get repetitive. Instead of this, the programmer can
define default values for parameters. This is done by setting the values when the parameter
is first defined. Here is an example script for this:

Def bacon(x=0):
Print(x)

bacon(1)
bacon()
bacon(23)

This should produce the following output:

1
0
23

Notice that when we called bacon the second time, there was no argument given — and
yet, there was a 0 that printed out. This is a default that is assigned automatically in such
cases when no arguments are given.

Returning Values

If a programmer wishes to use the value that the previous spam (or eggs) function, then he
could rewrite it so that it makes use of the return command.

>>>def spam(x):
… Return x**2


This can be used to do some fun things. Check out the following:

>>>print(square(3))
9
>>>print(square(square(3)))
81
>>>10+square(2)
14
>>>y=square(10)
>>>y
100

CHAPTER 18: Classes

Object Oriented Programming

Object oriented programming (OOP) is an approach to programming where the objects are
defines using methods (actions, functions, or events) and properties (characteristics,
values). This results in a more readable and more reusable code.

Take for example, a scenario where you have to write a program in order to keep track of a
group of motorcycles. Each of these vehicles have different characteristics, such as color,
mileage, etc. However, all of these perform the same basic actions such as accelerating,
braking, and swerving in and out of traffic. So instead of writing a piece of code separately
for each of these motorcycles, one can simply create a class for it—this can serve as the
“blueprint” for each of the objects.

Constructing Classes

A “class” is basically anything that can be said to be the generic description of the object
in question. In the Python programming language, a class method (an event, function, or
action) is defined. This is done using the following structure:

Class <<name>>:
Def <<method>> (self [, <<optional arguments>>]):
<<Function codes>>

Let us discuss this in detail. First, the object is defines using the keyword ‘class’, the name
that we want, and the colon as a punctuation. The methods are defined as in a normal
function—a single indent with ‘self’ as the first argument. So the following can serve as
the example class for our motorcycles:

Class Motorcycle:
Def brakes(self):
Print“Braking”
Def accelerates (self):
Print “Accelerating”

Note that the first name of the classes should have a capitalized first name. This is quite a
common convention, though it is not a technical requirement from the language. Also, the
example is a type of “encapsulation”, where the instructions for processing are defined as
a part of a different structure for reuse in the future.

How is this used? Once the class is created, then one will have to program an object for
each of the class’s instances. In the Python language, programmers create new variables
for each of these instances. Here is an example:

Motorcycle1= Motorcycle() # This is the instance for the motorcycle
Motorcycle2 = Motorcycle()

#Now, the object method is used like
Motorcycle1.brakes()

By using the parentheses (also called “calling in” the class), you can tell Python that you
wish to create not just a copy of the class definition but an instance. You would have to
create a different variable for each motorcycle. However, each of these objects can now
take advantage of the different attributes and class methods, so you would not have to
write a different accelerate and brake function for each of these vehicles.

Properties

As of now, all of the motorcycles in the previous sample code look the same. Since that is
unacceptable, let us try to give them some properties to make them unique.

In Python programming, a property is simple a variable specifically paired to a given
object. In order to assign a property, it is written as:

Motorcycle1.color=”Blue”

Then, this value is retrieved as:

Print motorcycle1.color

For purposes of convention, the functions are written to get (retrieve) and set (assign)
properties not set to be “read-only”. Here is an example:

Class motorcycle:
…previous methods…

Def set_owner(self,Owner_Name): #This part sets the “owner“ property.
Self._owner=Owner_Name

Def get_owner(self): # This part will retrieve the same property.
Return self._owner

You might have noticed the underscore that is before the name of the property. This is a
way to hide the name of the variable from users.

Starting from Python 2.2, the programmer can also define the example we provided above
so that it looks like any normal variable:

Class motorcycle:
…previous methods…
Owner=property(get_owner, set_owner)

Then, when you call in a way like mymotorcycle.owner=”John Doe”, the function
set_owner is called transparently instead.

Class Extension

In the event that a programmer will need to place additional functions to the class but is
reluctant to change the code (perhaps fearing that this can mess up programs depending on
the current version), he can “extend” the class as a solution. When this is done, all the
parent methods and properties are inherited while new ones can be added. As an example,
one can add a start_motorcycle method to the class. In order to extend classes, the
programmer will have to supply the parent’s class name in parentheses right after the new
class name. This is shown below:

class new_motorcycle(motorcycle):
Def start_motorcycle(self):
Self.on=True

The new class will extend the parent class.

Note that when attributes and methods are passed down in hierarchies to new classes, the
process is referred to in Python as “inheritance”.

Special Class Methods

In the Python language, the special methods’ names begin with double underscores (“__”)
and end with the same. For example, a special method __init__ has been used to initialize
newly created object states. As an example, the programmer can create not just a new
motorcycle model but also set its brand, year, model, and other attributes on a single line.
This is opposed to expending additional lines for each of the attributes.

Here is a demonstration:

Class new_motorcycle(motorcycle):
Def __init__ (self,model,brand,year):
# This sets all the properties
Self.brand=model
Self.model=brand
Self.year=year

Def start_motorcycle(self):
“””Start the motorcycle engine”””
Print “broooom broooom!”

If __name__ == “__main__”:
# This creates two separate instances of new_motorcycle, each of which has unique
properties
Motorcycle1 = new_motorcycle(“Diavel”,”Ducati”,”2016”)

Motorcycle1.start_motorcycle()

CHAPTER 19: Modules

In real life, we want all our files to be organized for easy storing and retrieval. Naturally,
this instinct would extend to our programming needs. This is primarily why Python
implemented modules.

A module allows the programmer to organize and logically arrange the code he has typed
in. By grouping all related code into a module, one can better read, understand, debug, and
use them. Modules in the Python language are objects that have arbitrarily named
attributes, which can all be bound and referenced.

Put another way, modules are files that consist of Python code. They can define classes,
functions, and variables. They can also include codes which can be executed. Below is an
example of a module. The code for the module with the name “spam” would normally be
in a file named “spam.py”. The example is that of a simple module:

Def print_func( par ):
Print “Hi:”, par
Return

Import Statement

Any Python source file can be used as a module through the execution of an import
statement in another source file. An import statement has the syntax:

Import module1[,module2[,…moduleN]]

When the Python interpreter encounters import statements, it will import the module in
case the module is found in the search path. The search path is a directory list, searched by
the interpreter before the module is imported. Let’s say, for example, that you would need
to import the module spam.py, the following command would have to be placed atop the
script:

#!/use/bin./python

Import support

Support.print_func(“Python”)

Once executed, the following result is shown:

Hi : Python

Modules have to be loaded only once, despite the number of times that it is imported. This
will prevent the execution of the module from occurring repeatedly, in case multiple
imports are called.

From…import Statement

The Python language’s from statement allows a user to import certain attributes from
modules and into the present namespace. The statement has the syntax:

From modname import name1[,name2[,…nameN]]

Let’s say that we need to import the eggs function from the bacon module, then the
following statement should be written:

From bacon import eggs

This statement will not import the whole module bacon to your current namespace —
instead, it adds the item eggs to the importing module’s global symbol table.

Fromm…import * Statement

It will also be possible to import all of the names from the module to your current
namespace through this import statement:

From modname import *

This will provide an easier way of importing all the items from the specified module into
your current namespace. However, make sure not to overuse this statement.

Locating Modules

In the process of importing modules, the interpreter searches for it in the following order:

Your current directory
When the module cannot be found, Python tries to look for it within a shell variable—
PYTHONPATH
When this still fails, the language tries to check the default path. In UNIX systems, this is
almost universally /usr/local/lib/python/.
The module’s search path is located in the sys system module as the variable sys.path. It
contains the present directory, PYTHONPATH, as well as the default (which depends on
the installation).

PYTHONPATH Variable

This is an environment variable, which consists of a list of directories. The
PYTHONPATH’s syntax is similar to PATH, a shell variable. Here is an example of a
Windows PYTHONPATH:

Set PYTHONPATH=c:\pythin20\lib;

As well, here is an example of the usual PYTHONPATH from UNIX and UNIX-like
systems:

Set PYTHONPATH=/usr/local/lib/python

Scoping and Namespaces

The variables are identifiers (names) that are mapped to objects. Namespaces are
dictionaries of names that are variables (keys) as well as their values (corresponding
variables).

Python statements are able to access variables in local namepsaces as well as in global
namespaces. If local and global variables are equipped with the same name, the local one
will shadow the global variable.

Every function is given its very own local namespace. The class methods also follow the
same rule for scoping just as any ordinary function.

The Python language can make educated guesses depending on whether specific variables
are global or local. This is done by assuming that variables assigned values in functions
are local. Therefore, if you need to assign values to global variables within functions, the
global statement will have to be used. Using the statement global VarName should tell
Python that VarName is to be considered as a global variable. Then Python stops searching
for the variable in local namespaces.

As an example, the variable spam is defined within the global namespace. Within the
spam function, spam is assigned a value, therefore having Python assume that it is a local
variable. However, the programmer accessed the local variable spam’s value before setting
it, so a result will appear instead: UnboundLocalError. To fix this, the programmer will
have to uncomment the global statement:

#!/usr/bin/python

Spam=3000
Def AddSpam():
#To fix the code, uncomment the following line:
*global Spam
Spam = Spam+1

Print Spam
AddSpam()
Print Spam

Dir() Function

The dir() function is a built-in one that will return a list of sorted strings, which in turn
contain the names defined by a specific module.

The list will contain the names of all the modules, functions, and variables that are defined
therein. Here is a simple example we can follow:

#!/usr/bin/python

#Use the built-in module math for import
Import math

Content=dir(math)

Print content

When the code above is executed, it produces a long list as a result. The special string
__name__ in the results is the name of the odule, while the __file__ on the result is the
filename from which this module has been loaded.

Locals() and Globals() Functions

These functions can be used by the programmer to return names in local and global
namespaces. This depends on the location from which they had been called.

If locals() has been called from within a function, it will then return all names that can be
locally accessed from this function. On the other hand, if globals() is called from this same
function, then it will return the names that can be globally accessed from that function.

Reload() Function

When a module is imported in a script, the top-level portion code of the module will be
executed just once. Therefore, if the programmer wishes to repeat the execution of the top-
level code, the reload() function may be used. What the function does is to import again a
module that has already been previously imported. The reload() function’s syntax is as
follows:

Reload(module_name)

In this syntax, the module_name part is the name of the one that you wish to reload—not
the string which contains the module name. For example, in order to reload a module
named spam, then simply type reload(spam).

Python Packages

A Python package is a file directory (hierarchial) which defines one Python application
environment consisting of modules, their subpackages, sub-subpackages, and so forth.

For example, consider a file entitles Bacon.py found in the directory Eggs. This line of
code appears in the file:

#!/usr/bin/python

Def Bacon():
Print “Bacon and Eggs”

In a similar manner, there are two other files which have different functions but with the
same name as that given:

● Eggs/Spam.py, which has the function Spam()
● Eggs/Juoce.py, which has the function Juice()

Then, let us put a new file named __init__.py inside the Eggs directory —
Eggs/__init__.py

In order to make all of the functions available once Eggs is imported, then one needs to
put the explicit import statements within __init__.py as shown here:

From Bacon import Bacon
From Spam import Spam
From Juice import Juice

After these lines are added to __init__.py, the programmer will have all these classes
available when the Eggs package is imported:

#!/usr/bin/python

#Now, the Eggs package is imported
Import Eggs

Eggs.Bacon()
Eggs.Spam()
Eggs.Juice

Once the code is executed, then the following is produced as a result:

Bacon and Eggs
Spam and Eggs
Juice and Eggs

In this example, we have taken just a single function in each of the files. However, you
can always keep multiple functions in the files. Different Python classes can also be
defines in these files, then packages can be created out of these classes.

CHAPTER 20: Python Idioms

Idioms are not just for the regular language—programming languages have idioms, too. A
great example is our Python, which is by nature a strongly idiomatic language. A
programming idiom is basically a means of expression of a recurring construct, something
that is not already a built-in feature of that language. In order to be “fluent” in “speaking”
any chosen programming language, one has to understand the idioms associated with it.
This allows the programmer to properly produce codes—“speaking” the language.
Because of Python’s philosophy about having a single optimal way to do things, it relies
strongly on its idioms for structure.

Basic Principles

● Aside from conflicting programming language philosophies, here are a couple of
conflicting acronyms: EAFP and LBYL. EAFP stands for [It’s] Easier to Ask
Forgiveness than Permission, while the latter means Look Before You Leap. While
LBYL may be more useful in real life, it is EAFP that is honored in Python.
Specifically, it spears to the programmer to use exceptions for checking errors. Any
action that may fail has to be put inside a try…except block.
● For managing resources such as files, use context managers (to be discussed in
detail in a later chapter). For ad hoc cleanup, use the finally statement. However, it is
preferred to write your context manager to encapsulate it.
● Do not use getter-setter pairs; instead, use properties.
● For dynamic records, it is better to use dictionaries. For static, records, classes
are preferred. For even simple classes, collections.namedtuple from the Python library
can be a good help. If records have the same field all the time, this is best made
explicit in a class. If the presence of the fields may vary, a dictionary is in order.
● For throwaway variables, use the underscore. This can be in instances like
discarding return values when tuples are returned, or when indicating that a specific
parameter is being igored. You may use *_, **_ in order to discard the keyword or
positional arguments being passed to a function. These symbols correspond to the
common *args, **kwargs parameters, though they are explicitly discarded. You may
also use them on top of named or positional parameters (after the ones you use). This
allows you to utilize some while discarding any excess.
● Except when you need to distinguish between “None”, 0, and [] or other falsy
values, use implicit True/False. Falsy values like the one given should have an explicit
check, such as ==0 or is None. And yes, that was “falsy” as opposed to “false”—falsy
refers to a non-Boolean that has an assigned value of false. (In the same vein, non-
Booleans with an assigned True value is called a “truthy”.)
● While else is completely optional, it is good practice to use it right after try,
while, and for instead of ending things at if.

Imports

For a good code practice, import only modules and not names (such as classes or
functions). Doing the latter gives birth to a new (name) binding, which may not always be
in sync with already exsisting binding. For example, for a module m which exists to define
a function f, having the function importing using from m import f would mean that m.f and
f may differ if either of them is affixed to (creating a new binding).

In actuality, this is often ignored especially for smaller-scale code. This is because
modifying modules after importing them is relatively rare. Both functions and classes in
such instances may be imported from modules in order for them to be referred to without
using a prefix. For large-scale robust code, however, this could be an important
convention as it can create bugs which can be very hard to find.

With low typing, the programmer can utilize a renaming import in order to abbreviate a
longer module name.

Import this_module_has_a_very_long_name as n1
N1.f() #tthis is a lot easier than a very long name,, which just as robust

Take note that using from in order to import subpackages or submodules from a specific
package is completely acceptable. Here is an example:

From O import sm # completely alright
Sm.f()
Operations

● In swapping values, simply use b,a=a,b
● In order to access attributes (particularly to call a method) for values that could
be an object or possible None, use the following:
a and a.x
a and a.f()
● For substring checking, you can use in

Data Types

You can use enumerate() for keeping track of the different iteration cycles over iterables:

For i, x in enumerate(l):
#…

This is as opposed to the following technique, which is considered an anti-idiom:

For i in range(len(l)):
X=l[i]
#…

The second line goes from the list to the numbers and then back to the list, which is
unpythonic.

Finding the first matching element

Python sequences have an index method, which returns the index of a specific value’s first
occurrence in the sequence. In order to find this first occurrence which satisfies a
condition, simply use next plus a generator expression. This is demonstrated in the
following code:

Try:
X=next(a for a, n in enumerate(l) if n>0)
Except StopIteration:
Print(‘No positive number’)
Else:
Print(‘The firs positive number index is”,x)

When the value is needed and not its index of occurrence, this can be directly obtained
through the following technique:

Try:
X=next (a for a in l if >0)
Except StopIteration:
Print(‘No positive number’)
Else:
Print(‘The first number is’,x)

The reason the code is constructed this way is two-fold. First, the exceptions will let you
signal a “no match found”, since they solve the problem of the semipredicate). Since a
single value will be returned and not an index, this cannot be returned in the value. Also,
generator expressions will let the programmer use an expression even without the need for
a lambda (a function which is “anonymous” or not bound down to a name) or for the
introduction of new grammar.

Truncating

In the case of mutable sequences, use the del function instead of reassigning it to a slice:

Del l[j:]
Del l[:i]

The anti-idiom for this is as follows:

L = l[:j]
L = l[i:]

The plain reason for this is that adding del makes your intention of truncating clear.
Slicing will create another reference pointing towards the same list since lists are mutable.
Unreachable data that is left over can be collected, though this is mostly done later. Instead
of this, deleting modifies the lists in-place — a method that is faster than creating slices
and then assigning them to existing variables. This also lets Python immediately single out
the deleted elements for deallocation, instead of waiting for the garbage collection to do
this later.

Admittedly, though, there are some cases when you would want the same list in 2 slices.
This is, however, rare in basic programming. It is also rare that one would want a slice of
the entire list, then using this slice to replace the original variable without changing the
other slice. This improbability is demonstrated in the following code:

M = l
L = l[i:j]

Instead of this, you can just try:

m=l[i:j]

Sorted list from iterables

You may create sorted lists directly from iterables, without having to make a list first and
then sort it. These also cover dictionaries and sets:

x={l,’a’,…}
y=sorted(x)
z={‘a’:1,…}
y=sorted(x)

Tuples

When going for constant sequences, always use tuples. While not a complete rule, it helps
the code become more Pythonic by making the intention of the programmer clear.

Strings

When checking for substrings, use the in function. However, do not use the function to
check for a single-character match. This will match substrings, returning spurious
matches. Instead of this, use a tuple with valid values. Let’s take the following code as an
example of what not to imitate:

Def valid_sign(sign):
Return sign in ‘+-’

This is wrong, since it will return True for the sign == ‘+-’. Instead of that, use a tuple as
follows:

Def valid_sign(sign):
Return sign in (‘+’,’-’)

Building Strings

If you would need to build a long string in increments, first build a list and then join using
‘ ‘ or new lines if you are building in a text file. Do not forget to use a final new line in
this case. This will be both clearer and faster that appending directly to a string, which is
oftentimes slow.

There are, however, a few optimizations in CPython that can help make simple appending
to strings fast. Appending strings in CPython 2.5+ as well as appending bytestrings in
CPython 3.0+ are all fast, but building Unicode strings (called unicode in Py2.X and
string in Py3.X) ad joining them are even faster. Remember to be aware of this when you
are expecting to manipulate a lot of strings — profile your code accordingly.

Let’s take the following code as an example of what you shouldn’t do:

X=’ ‘
For y in l:
X+=y

The above code would make a new string for each iteration, since strings are immutable.
Instead of that, use the following code:

#…
#x.append(y)
S=’ ‘.join(x)

You may also use generator expressions, which may prove to be very efficient:

S = ‘ ‘.join(f(y) for y in l)

You can also use StringIO for mutable string-like objects.

Dictionaries

You can use the following code to iterate over keys:

For z in y:


For iterating over values in Python 3:

For x in y.values():


For iterating over values in Python 2 (note that dict.values() returns a copy in Py2.X):

For x in y.itervalues():


For iterating over keys and values in Python 3

For z,x in y.items():


For iterating over values in Python 2 (note that dict.items() returns a copy in Py2.X):

For z, x in y.iteritems()


On the other hand, anti-idioms would be:

● For z, _in y.items(): instead of for z in y:
● For _, x in y.items(): instead of for x in y.values()


CHAPTER 21: Performance Tips

We have already mentioned quite a few times that Python is not the fastest of all the
programming languages when it comes to the interpreter. But then again, what kind of
software would it be if it cannot be modified for performance? In this chapter, we will be
discussing the different tips you can use to optimize Python.

Ever since about 1996, people have been writing about how to make Python faster. That
means there is a large wealth of information that may or may not work for you. This
chapter will give you a plethora of tips that will allow you to mix and match whatever
suits your style and your system. Then again, nothing’s stopping you from implementing
all of these.

The Lowdown on Optimizing

First off—the Python implementation. We had given you a lot of these at the start. When
choosing any of these, make sure that you are choosing based on what you really like to
use and on what your job demands—not simply because this book or anyone else told you
that this implementation is faster than the rest.

Once you have begun using the software and played around with it for a bit, you will be
able to find what is making the program slow. Get the program to yield correct results,
then run the results so you can check whether or not the correct program is slow. If you
find the program to really be slow, then you can use profiling techniques to show you
which parts of the program consume the most time. There are comprehensive by snappy
suites available for you to use afterwards, which aid in making sure that any future
optimization does not affect the correct way that the program runs.

In a nutshell, you have to:

1. Get the program right.
2. Test that it’s really right.
3. Profile if it is slow.
4. Optimize.
5. Repeat from step 2.

There are certain ways to optimize which amount to a better programming style—such as
the idioms we had discussed earlier. Make sure that you learn these as you go along with
Python programming.

Profiling the Code

The first tangible step in trying to speed up your program is analyzing exactly where the
bottlenecks may lie. It will hardly make sense to try and optimize a piece of code that will
not be executed, or one that already runs at blazing speeds. There are two modules that
can be used to help locate any code hotspots you might have—trace and profile. You can
also use the timeit module, if you are using Python 2.3 and later.

There are actually a number of modules included in Python that will allow for
optimization and profiling. One of these can be used to profile a set of functions’
execution. Let’s say that your primary function is called test1, and that it takes no
argument. You will then want it to execute under the profile module’s control. This will be
the simplest way it is done:

Import profile
Profile,run(‘main()’)

Once the main() is returned, the profile module would then print a table of the function
calls with the execution times. This output may then be tweaked through the stats class
also included in the module. From Python 2.4 onwards, profile is also allowed to profile
the time being consumed by Python’s builtins as well as extension module functions.

Hotshot and cProfile Modules

The hotshot package has been available since Python 2.2, as a replacement for profile. In
spite of this, the cProfile package has been the one more preferred. The module has been
written in C, so using either could result in a smaller hit to the overall performance. This
will allow you a better idea of how exactly the application is performing. In the
Tools/scripts of the distribution, the hotshotdomain.py program can also be found. This
will make it better for the programmer to run the code from the command line under
hotshot control.

Trace Module

Being open-source, even Python modules have their spin-offs. One for the profile module
we mentioned earlier is the trace module, which was originally written to help perform
test coverage. It has been since modified by the Python community, and can be found in
the Tools/script directory in your Python distribution back in Python 2.0’s release. It has
been added to the standard library (Lib directory) starting Python 2.3—it can be copied to
the local bin directory, and the execute permission can be set from there. It will be easy to
run this from the command line, tracing the execution of whole scripts:

% trace.py -t eggs.py spam

In the 2.4 release, it will be even easier to run—simply type python -m trace. You can also
use pydoc trace in order to view the documentation of the trace module.

Visualizing the Profiling Results

You can use the following to visualize the results of your profiling attempts:

RunSnakeRun. This is a GUI tool that will visualize the profile dumps from the cProfile
module using square maps. The function and method calls can be sorted by different
criteria, and the source code can also be displayed beside the visualization and the call
statistics.

Gprof2Dot. This is a tool based on Python which allows you to transform the profiling
results into a graph. This graph can then be converted into SVG or PNG.

PyCallGraph. This is a module which helps you create call graphs for your Python
programs. It can generate a file in PNG, which shows the function calls of the modules as
well as their links to other function calls. It can also show the amount of times the function
is called, as well as the time the program spent within that function.

PyProf2CallTree. This is a script that will help you visualize the profiling data you
collected through the cProfile module. It uses the kcachegrind calltree analyzer.

ProfileEye. This is a front end to Gprof2Dot. It is browser-based, and uses d3.js in order
to declutter the visual information.

Sorting

Sorting the list of the basic Python objects is a pretty efficient process. This method for
lists uses a comparison function (optional) as the argument which is then used to change
the behavior of the sorting. This is convenient, even though it can slow down the sorting
process itself—as it runs, the comparison function has to be called a lot of times. Back in
Python 2.4 and older, you will have to use the built-in sort’s key argument instead—this
should have been the fastest way of sorting.

If you are indeed using Python 2.4 or any older versions, then the following advice should
be applicable—take heed as it comes from Guido van Rossum himself.

To speed up the sorting process, create a list of tuples where a sort key is the first element.
This key will properly sort through the default comparison. The second element should be
the original list element. Also known as the DSU (DecorateSortUndecorate), it is further
known to Pythonistas as the Schwartzian Transform.

For example, you have are with a list of tuples that you would want to arrange by the nth
field of the tuple. This function should look like:

Def sortby(alist,n):
Xlist=[(xn],x) for x in alist]
xlist.sort()
Return[val for (key,val) in xlist

Another thing you can easily achieve as well is matching the preset list sort method’s
behavior (also called sorting in place).

Def sortby_inplace(alist,y):
Alist[:]=[(x[n],x) for x in alist]
Alist.sort()
Alist[:]=[valfor(key,val) in alist]
return

Concatenating Strings

This section will be effective based on the type of Python implementation you are running.
Concatenation tends to be fairly fast for later versions, but then again you might be using
the one which came when you first had your computer a few years back.

Remember that strings are immutable in Python. This is important to remember, since
many Python novices overlook this, thus leading to code-fatal programming mistakes. The
immutable state of strings can lend itself into both advantages and disadvantages. Among
the former is the fact that strings can be used as dictionary keys, and multiple variable
bindings can share individual copies. In fact, one- and two-character strings are
automatically shared in Python. On the down side, however, a programmer cannot do
something like “change all x’s to y’s” in any string. Instead, a new string with all the
desired properties will have to be created. This process of continual copying may be a
source of inefficiencies in some Python programs.

As an illustration, here is something that you would want to avoid:

a=” ”
For substring in this list:
a += substring

Instead, use the a=””.join(list) line. The former example is actually a common mistake
Python novices have in the process of building large strings.

In the same vein, if you generate bits of a string in a sequential manner, avoid the
following:

a=” ”
For b in list:
a+=a_function(b)

Instead, use:

alist=[a_function(elt) for elt in anotherlist]
a=” ”.join(alist)

Also, avoid the following:

Out=”<html>”+head+prologue+query+tail+”</html>”

Instead of that, use:

Out=”<html>”%s%s%s%s</html>” % (head, prologue, query, tail)

For readability, it is even better to use a dictionary substitution (this, however, will not
have anything to do with efficiency aside from your own as a programmer).

Out=”<html>%(head)s%(prologue)s%(query)s%(tail)s</html>” % locals()

The last couple of examples are both going to be much faster than the first, and even more
so when they are piled up over multiple CGI script executions. They are also easier to
modify if necessary. On top of this, the addition of the rich comparisons in Python 2.X has
made the slow way even slower. If you are using that branch, it will take your virtual
machine even more time to figure out how the two strings will be concatenated. Also, do
not forget that all the method look-up will be done by Python at runtime.

Loops

Some looping constructs are supported by Python. Of them, the most commonly used
statement is the for. It works by looping over the elements of the sequence, each being
assigned to the loop variable. If the loop’s body is simple, then the for loop’s interpreter
overhead may be a substantial chunk of the entire overhead. At this point, the map
function will be handy.

You may visualize the map function as for which has been moved into C. The sole
restriction is that the map’s loop body should be a function call. Here is an example—this
one loops over the list of words and converts them to the upper case:

Thislist=[]
For word in thatlist:
Thislist.append(word.upper())

You can instead use the map function to have the loop pushed from your interpreter into a
compiled C code:

Thislist=map(str.upper,thatlist)

It doesn’t even matter if you have plain old Python 2.0, as list comprehensions have been
added from this version onwards. These provide a more compact (syntactically) and a
more efficient way to write the for loop:

Thislist=[s.upper() for s in thatlist:

The generator expressions have been added since Python 2.4. These function in about a
similar way as map or list comprehensions. However, they avoid the need for additional
overhead (i.e., having to generate the entire list all at once). Instead of this, a generator
object which can be incrementally iterated is being returned:

Iterator=(s.upper() for s in thatlist)

Whether the method you are using is appropriate will depend on which version of Python
you will be using. Another consideration will be the characteristics of the data that you are
manipulating.

Avoiding the dots

Suppose you will not be able to use a list comprehension or map? Then you may be stuck
with using the for loop. This will lend your program to another inefficiency. The
word.upper and thislist.append are function references which are being re-evaluated every
time through the loop. Instead, you can replace the original loop with the following code:

upper=str.upper
thislist=[]
append=thislist.append
for word in thatlist:
append(upper(word))

However, use this technique with caution. It will be more difficult to maintain once the
loop starts to get larger. Unless you already are, you will first have to be very acquainted
with the usage of upper and append.

Local Variables

Without the map version, the last speedup available for the for loop will be the use of local
variables as long as possible. If the loop above has been cast as a function, upper and
append will become local variables. The Python language will access these local variables
a lot better than global variables. Take a look at the following example:

Def func():
Upper = str,upper
Thislist=[]
Append=thislist.append
For word in thatlist:
Append(upper(word))
Return thislist

Initializing Dictionary Elements

Let’s say that you are building a dictionary containing word frequencies, and that you have
already broken up the text into word lists. You may then execute something similar to the
following code:

Wdict={}
For word in words:
If word not in wdict:
Wdict[word]=0
Wdict[word]+=1

The exception is that for the first time, every time that a word is seen then the test of the if
statement will fail. If you will be counting a large amount of words, then many of them
will probably be recurring multiple times. In a time where the value’s initialization will
only be occurring once and the value’s augmentation will occur multiple times, it will be
better to use a try statement. Check out the following code:

Wdict={}
For word in words:
Try:
Wdict[word]+=1
Except KeyError:
Wdict[word]=1

It will be important to catch the KeyError exception that you are expecting. At the same
time, you should not use a generic except clause in order to avoid attempting to recover
from exceptions which cannot really be handled using statements in the try clause.
Another alternative is to use the get() method, available since Python 2.0—this means that
if you downloaded a fresh Python implementation when you started this book, this is the
best thing to use. This method will return a default value when the desired key cannot be
found in the dictionary. This will simplify the loop.

Wdict={}
Get=wdict.get
For word in words:
Wdict[word]=get(word,0)+1

In addition, if the value that the dictionary stores is a mutable list (object), you may use
dict.setdefault:

4 wdict.setdefault(key,[]) .append(new_element)

You might be thinking that this will avoid having to look the key up twice, but it doesn’t—
not even in Python 3.x. At least, however, the double look up is being performed in C.

Another available option is using the defaultdict:

From collections import defaultdict

Wdict = defaultdict(int)

For word in words:
Wdict[word]+=1

Overhead for Import Statements

The import statement can be used almost anywhere. It will often be useful to place these
inside functions in order to restrict the visibility and also to help reduce the start-up time.
While the interpreter is optimized to avoid the importation of the module multiple times,
the repeated execution of an import statement will affect (sometimes seriously so) the
performance of the program in certain circumstances.

Check out the next two examples of code:

Def dothis1():
Import string #this will import the statement inside function
String.lower(‘Spam’)

For num in range (100000):
Dothis1()


Or:

Import string # this will import statement outside function
Def dothis2():
String.lower(‘Spam’)

For num in range(100000):
Dothis2()

In the above examples, dothis2 will be running significantly faster than dothis1, despite
the string module reference being global in dothis2. Then again, string methods (which
have been introduced in Python 2.0) can be used, totally avoiding the need for import and
making the program run even faster:

Def dothis3():
‘Spam’.lower()

For num in range (100000):
Dothis3()

Notice that putting the import within a function may speed up the module’s initial
recording, especially when the imported module may not even be required. This is usually
seen as a case of “lazy” optimization—avoiding the work (in this case, an expensive case
of importing) until it is confirmed that the said work is required. This can only be a
significant optimization in case the module would not have been imported in any way,
from any module. Once the module is already loaded—like in the case of a lot of standard
modules such as re or string—avoiding the import will not save anything. To see the
modules that have already been loaded in the system, you can check in sys.modules.

You can also use the following method to do a good lazy import:

Email=None

Def parse_email():
Global email
If email is None:
Import email


In this example, the email module will only have to be imported once, once parse_email()
is invoked.

Data Aggregation

In Python, the overhead for function calls is quite high. This is especially tru when
compared with a builtin function’s execution speed. This suggests that when appropriate,
data aggregates should be handled by functions. Here is an example (a contrived one):

import time
y=0
Def dothis1(s):
Global a
A=a+i

List=range(100000)
X=time.time()
For s in list:
Dothis1(s)

Print”%.3f”% (time.time()-x)

Compare the above example with the next one:

Import time
Y=0
Def dothis2(list):
Global x
For s in list:
A=a+i
List=range(100000_
X=time.time()
Dothis2(list)
Print”%.3f”% (time.time()-t)

Even if written in Python, the second example will still run at around four times faster. If
this is written in the C language, the difference in speed would have been more profound,
as this involves using a C for loop instead of a Python one, while also removing many of
the code’s function calls.

Going Lazy

Well, we already talk of going lazy a bit in the last section, so let’s take a break from the
technical things and focus on that one. Take note that periodically, Python performs some
checks. Specifically, it will decide during such times whether or not it should let another
thread run. It also things of whether or not a pending call should be run (these calls are
typically established by signal handlers).

Most of the time, these checks do not result in anything for Python to do. That means each
pass these checks make around the interpreter loop can cause things to slow down. In such
circumstances, we can use the setcheckinterval function within the sys module—this can
be called to tell the interpreter exactly how often you would want these periodic checks to
be performed. Before the advent of Python 2.3, this has been defaulted to 10. Since then, it
had been raised to a hundred. So if you are not expecting to catch many signals (and if you
are not running with threads), you can set this to an even larger value to help nudge the
interpreter’s performance.

Instead of range, use xrange

This will not apply if you are using the Python 3.X branch, where the range function will
provide an iterator for arbitrarily-sized ranges, and where the xrange function does not
exist.

However, if you are using other Python versions, this may be useful. Python provides two
ways of getting a range of numbers—xrange and range. Most programmers already know
range, since the name makes it quite obvious. However, xrange is a lot less known. It is a
generator object, which is equivalent to the following code (exhibited in Python 2.3):

Def xrange(start,stop=None, step=1):
If stop is None:
Stop=start
Start=0
Else:
Stop=int(stop)
Start=int(start)
Step=int(step)

While start<stop:
Yield start
Start += step

All of this, except that the implementation is purely in C.

The xtrange function does have its limits. More specifically, it will only work with int$—
you will not be able to use it with float$ or long$ as they will also be converted to int$ as
demonstrated above.

It would, however, save you a significant amount of memory. Also, unless the yielded
objects are stores somewhere, only a single yielded object will be there at a time. The
difference, then, will be this: when the programmer calls the range function, it will create
a list which contains a certain number of objects (long, int, or float). All these objects will
be created at once, with all of them existing all at the same time. This will be a significant
issue when the amount of numbers is very large.

On the other hand, xrange creates exactly zero numbers immediately—just the range
object. The number objects will be created once the programmer pulls on the generator,
such as done by looping through it. Here is an example:

Xtange (sys.maxint)

No numbers here as instantiated—there are no loops, and no calls to .next. For this reason,
the code will instantaneously run. If instead you use range here, Python will be locking up
—it would become too caught up allocating the number objects for sys.maxint. This
number could rise up to about 2.1 billion on the normal PC. At this point, it will not do
anything else—instead, it will eventually exit from running out of memory.

In the Python versions before the advent of 2.2, the xrange objects will also support
optimizations such as better membership testing (a in xrange(b)). Because of lack of use,
this was eventually removed.

Remapping functions at Runtime

Let’s say that you have the following:

Class Test1:
Def check(self,x,y,z)
If x==0:
Self.str=y*100
Else:
Self.str=z*100

x=Test1()
Def example():
For b in xrange(0,100000):
X.check(b,”y”,”z”)

Import profile
Profile.run(“example()”)

Suppose, after this, that the function will get called from someplace else a number of
times. The check will be having the if statement slow you down for each time except for
the first, so you can do this instead:

Class Test2:
Def check(self,x,y,z)
Self.str=y*100
Self.check=self.check_post
Def check_post(self,x,y,z):
Self.str=z*100

S=Test2
Def sample2():
For b in xrange(0,100000):
S.check(b,”y”,”z”)

Import profile
Profile.run(“sample2()”)

You might find that the example can be quite inadequate, however if the if statement
comes with lots of dots or other markers of a complicated expression, you can save
yourself from evaluating it again and again if you know that it can only be true for the first
time.

CHAPTER 22: Implementations Galore

Near the beginning of this book, we talked about the different “compilers” or
implementations available in Python. Just as there is a battle raging about which Python
version to use, many are also debating about which implementation is best. Now that you
have learned what you can in basic Python programming, you should be ready for this
discussion as well. Our objective in this chapter will not be to decide which
implementation is best, but to try and define each according to what they can do.

Notice that when people talk about the “Python” language, most of them do not just mean
Python but also CPython, the default Python implementation. In reality, the term “Python”
refers to the language’s specification—something that can then be implemented in
different ways. Python is basically an interface (which nullifies the common question of
whether Python is compiled or interpreted—these are characteristics of implementations).

As you go through the different Python implementations, you will inevitably hear about
the terms “machine code” and “byte code”. There is a good difference between the two.
Machine code is what C compiles to, something that is subsequently run through the
processor directly. Each of the instructions sent to your machine’s CPU tells it to move
things around. On the other hand, bytecode is where Java compiles to, something that is
then run using the Java Virtual Machine. This is in essence an abstraction—that of a
computer, which has the same ability to execute programs. Each of the instructions are
being handled by its virtual machine, in turn interacting with your computer.

When it comes to performance, we can shorten the comparison to this: bytecode can be
very portable and secure though machine code beats it when it comes to speed. Because of
its nature, machine code can look different depending on the machine you are
programming on. This makes it optimized depending on your setup. Bytecode, on the
other hand, can be homogeneous.

Many beginners to Python are told that Python is a “compiled language” because of its
.pyc files. There’s only a half truth to this, as the .pyc is a compiled bytecode. This is then
interpreted. This means that if you have run the Python code once, having the .pyc file will
make it run faster the next time. This is because the bytecode no longer has to be
compiled.

CPython. This is the de facto standard, and the reference implementation which has been
written in C. We have discussed this near this book’s start, but it is worthwhile to note
some of its other defining features. CPython works by compiling the code to intermediate
bytecode. This is then interpreted later by a virtual machine. This implementation provides
the best compatibility level between Python’s packages and the extension modules of C.

If you will be writing code that is open source and you wish to reach as much audience as
you can, then it is best to target CPython. Besides, this is the sole implementation option,
if you will be relying on C functions for your code to function. Note that all the Python
versions (that of the language itself) are implemented in C—this is because of CPython’s
use as the reference implementation.

PyPy. This is an interpreter that is implemented in RPython—a restricted and statistically-
typed Python subset. As previously mentioned, it has a just-in-time compiler with support
for multiple backends (CLI, C, and JVM).

PyPy has been hailed by some stalwarts as the “future of Python”. This may be a justly-
earned title—it is built for maximum compatibility with the CPython reference, while also
improving performance. So if you wish to increase your code’s performance, PyPy should
be on your radar—based on some benchmarks, it can be more than 5 times faster than
CPython!

As of this point, PyPy has released a beta that targets Python 3. PyPy’s default version
supports version 2.7.

Jython. This is an implementation that compiles the code into Java bytecode. This is then
executed by a Java Virtual Machine (JVM). It is also able to additionally import and
utilize any Java class as it would a Python module.

Jython is best used if you anticipate interfacing with an existing codebase in Java. It can
also be used for any reason when you need to code in Python for the JVM. As of the time
of this writing, it supports Python 2.7.

IronPython. This is an implementation meant for the .NET framework. It has the ability
to use both .NET and Python libraries, while also retaining the ability to expose the code
in Python to other languages within the .NET framework.

It also provides access to the Python Tools for Visual Studio, which then directly
integrates into the development environment of Visual Studio. This makes it perfect for
Windows-based developers.

PythonNet. This is a package (also called Python for .Net) which helps provide near-
flawless integration of natively installed Python installations together with the .NET CLR
(Common Language Runtime). This is an inverse approach than the one taken by
IronPython. However, instead of competing, the approach comes across as
complementary.

Together with Mono, this package enables the native installations to work across non-
Windows operating systems—Linux and OS X, as examples. This allows the native
Python installation to operate in the .NET framework. It can also be run alongside
IronPython without issues.

Cython. This is a Python superset which also includes all the bindings needed to call the
different C functions. It allows the programmer to use thes extensions to the Python code.
It also allows the addition of static typing into the existing Python code, allowing
compilation and letting it reach performance akin to C.

In this view, it can be seen as similar to PyPy. However, it is not the same. In this case,
typing in the code is being enforced before it is passed to a compiler. In comparison, PyPy
enforces writing in simple Python while the compiler itself is responsible for adding
optimizations.

Numba. This is also a “just-in-time” compiler, however it adds the feature to an annotated
Python code. In the simplest sense, the programmer just gives Numba the hints, and it
takes care of the optimization. This comes as a part of Anaconda, a distribution that offers
a set of packages needed for data analysis and management.

Ipython. This is different from all that has been discussed here—it is a computing
environment which offers an interactive environment, with added support for browser
experience, GUI toolkits, and more.

Psyco. This is an extension module, and is one of the first just-in-time efforts. It has since
been marked as “dead” (unmaintained), and its lead developer now works for PyPy.

Note that all these differences wouldn’t exactly tell you which implementation to use
unless you have a very specific need that can be answered by one or two among the list. In
the first place, the list that we have is not even exhaustive. All Python implementations
may differ in their behavior, and they surely differ in the way the Python source code is
tossed around. However, these differences rarely play a huge part in the end result of the
code’s capabilities. As it goes, the differences tend to disappear over time.

Spotlight on PyPy

Earlier, we mentioned an implementation that some are calling the “future of Python”. We
included that for a reason. Despite what we said in the preceding paragraph, we felt it was
important to shed more light on this implementation alone to at the very least give you a
more detailed idea of how implementations work (and how complicated they are).

Remember how CPython is written in C, and some others in Java and .NET? Well, PyPy is
a Python implementation written in Python. If you remember the previous definition of
Python as a language, this is just a wee bit paradoxical. And here’s where things are going
to get confusing.

We already mentioned how machine code is faster than bytecode. Someone then had the
great idea to compile some of the bytecode and run it as native code. This will, inevitably,
cost us something—like the time it would need to compile the bytecode. However, the end
result would make the implementation much faster! This sort of thinking is what lied
behind the just-in-time compilation, affectionately called JIT by its users.

The hybrid technique will produce a product that combines the benefits of both compilers
and interpreters. In the most basic terms, a JIT system like PyPy will use compilation in
order to speed up interpreted systems.

Here is a common approach that is being taken by JITs:

1. Bytecode that has to be frequently executed needs to be identified.
2. This is then compiled into native (machine) code.
3. The result is cached.
4. When the exact same bytecode is set to run, the pre-compiled machine code will be
grabbed for speed boosts.

For many, this is what makes PyPy so unique—not that it is alone, since there have been
other efforts before. The thing is, PyPy is so much more than its predecessors—it also
aims to be light on memory, support cross-platform compatibility, and be stackless-
supportive. As mentioned earlier, it is also highly compatible with the de facto CPython
compiler, meaning it can also run Django, Flask, and similar others.

Despite all the sunshine and rainbows, there is also a lot of confusion surrounding PyPy.
For example, someone even submitted a proposal to create a “PyPyPy”—a nonsensical
attempt to create an even faster implementation. Part of the reason for the confusion is
because PyPy is a couple of things:

1. As mentioned earlier, it is an interpreter that is written in Python–RPython to be exact, a
subset of the language with static typing. In the Python language, it is mostly impossible
to rigorously reason about types. Why? Here is an example:

a=random.code([1,”spam”])

This is a valid Python code, but what is the typeof the x? How can one reason about
variable types when these are not even strictly enforced? Some flexibility is sacrificed in
Rpython, but instead it is a lot easier to reason about things such as memory management.
This allows for a good deal of optimization.

2. PyPy is a type of compiler that compiles the Rpython code for different targets. Of
course, it also adds in JIT. By default, the platform is C (as in, Rpython-to-C), though
others such as JVM can also be added.

Now, how do these two items add to the confusion? Let’s take this further. Think of the
first definition as an interpreter that is written in RPython. It will take the user’s code,
compiling it down into bytecode. However, since the interpreteris written in Python,
another implementation is needed to interpret it.

The creators of PyPy could have just used CPython, but that is not very fast. Instead, the
second definition of PyPy comes into play. This is also called the “RPython Toolchain”. It
compiles the entire PyPy interpreter to code for a different platform, such as CLI, JVM, or
C. Again, JIT is thrown in—adding this to the interpreter essentially generates its very
own compiler. If you think of it, it is kind of crazy—you are compiling an interpreter, in
the process adding another standalone separate compiler. No matter how roundabout it
may see, it works.

The overall result is an executable, a standalone one that interprets the source code while
exploiting optimizations through JIT. If you dare to think about the abstract nature of it all,
you can be writing an interpreter for any language, throw it to PyPy, and get the JIT magic
to work. This is because the interpreter focuses on the optimization of the interpreter itself,
not just the details of the language that is being interpreted.

CONCLUSION

Python is a fun language. That alone makes it stand out as not every language can claim
the simplicity and the readability that are inherent to Python. This also makes Python very
useful, as its ease of learning and deployment can make it suitable for a number of tasks
(though the same trait also arguably disqualifies it for others).

So what are you waiting for? This book has given you all that you need to jump in. The
next step for you is to apply what you have learned, seek further study, and master the
Python language! Now that Python programmers are gaining prominence, you have just
gained a new qualification that can take you to even greater heights.

You might also like