Read Programming Python Online

Authors: Mark Lutz

Tags: #COMPUTERS / Programming Languages / Python

Programming Python (194 page)

BOOK: Programming Python
7.64Mb size Format: txt, pdf, ePub
ads
Adding new buttons in new components

One obvious
way to reuse the calculator is to add additional
expression feature
buttons—
square roots, inverses, cubes,
and the like. You can type such operations in the
command
-line pop ups, but buttons are a
bit more convenient. Such features could also be added to the main
calculator implementation itself, but since the set of features that
will be useful may vary per user and application, a better approach
may be to add them in separate extensions. For instance, the class in
Example 19-22
adds a few
extra buttons to PyCalc by embedding (i.e., attaching) it in a
container.

Example 19-22. PP4E\Lang\Calculator\calculator_plus_emb.py

"""
#############################################################################
a container with an extra row of buttons for common operations;
a more useful customization: adds buttons for more operations (sqrt,
1/x, etc.) by embedding/composition, not subclassing; new buttons are
added after entire CalGui frame because of the packing order/options;
#############################################################################
"""
from tkinter import *
from calculator import CalcGui, getCalcArgs
from PP4E.Gui.Tools.widgets import frame, button, label
class CalcGuiPlus(Toplevel):
def __init__(self, **args):
Toplevel.__init__(self)
label(self, TOP, 'PyCalc Plus - Container')
self.calc = CalcGui(self, **args)
frm = frame(self, BOTTOM)
extras = [('sqrt', 'sqrt(%s)'),
('x^2 ', '(%s)**2'),
('x^3 ', '(%s)**3'),
('1/x ', '1.0/(%s)')]
for (lab, expr) in extras:
button(frm, LEFT, lab, (lambda expr=expr: self.onExtra(expr)))
button(frm, LEFT, ' pi ', self.onPi)
def onExtra(self, expr):
text = self.calc.text
eval = self.calc.eval
try:
text.set(eval.runstring(expr % text.get()))
except:
text.set('ERROR')
def onPi(self):
self.calc.text.set(self.calc.eval.runstring('pi'))
if __name__ == '__main__':
root = Tk()
button(root, TOP, 'Quit', root.quit)
CalcGuiPlus(**getCalcArgs()).mainloop() # -bg,-fg to calcgui

Because PyCalc is coded as a Python class, you can always
achieve a similar effect by extending PyCalc in a new subclass instead
of embedding it, as shown in
Example 19-23
.

Example 19-23. PP4E\Lang\Calculator\calculator_plus_ext.py

"""
#############################################################################
a customization with an extra row of buttons for common operations;
a more useful customization: adds buttons for more operations (sqrt,
1/x, etc.) by subclassing to extend the original class, not embedding;
new buttons show up before frame attached to bottom by calcgui class;
#############################################################################
"""
from tkinter import *
from calculator import CalcGui, getCalcArgs
from PP4E.Gui.Tools.widgets import label, frame, button
class CalcGuiPlus(CalcGui):
def makeWidgets(self, *args):
label(self, TOP, 'PyCalc Plus - Subclass')
CalcGui.makeWidgets(self, *args)
frm = frame(self, BOTTOM)
extras = [('sqrt', 'sqrt(%s)'),
('x^2 ', '(%s)**2'),
('x^3 ', '(%s)**3'),
('1/x ', '1.0/(%s)')]
for (lab, expr) in extras:
button(frm, LEFT, lab, (lambda expr=expr: self.onExtra(expr)))
button(frm, LEFT, ' pi ', self.onPi)
def onExtra(self, expr):
try:
self.text.set(self.eval.runstring(expr % self.text.get()))
except:
self.text.set('ERROR')
def onPi(self):
self.text.set(self.eval.runstring('pi'))
if __name__ == '__main__':
CalcGuiPlus(**getCalcArgs()).mainloop() # passes -bg, -fg on

Notice that these buttons’ callbacks force floating-point
division to be used for inverses just because that’s how
/
operates in Python 3.X (
//
for integers truncates remainders
instead); the buttons also wrap entry field values in parentheses to
sidestep precedence issues. They could instead convert the entry’s
text to a number and do real math, but Python does all the work
automatically when expression strings are run raw.

Also note that the buttons added by these scripts simply operate
on the current value in the entry field, immediately. That’s not quite
the same as expression operators applied with the stacks evaluator
(additional customizations are needed to make them true operators).
Still, these buttons prove the point these scripts are out to
make—they use PyCalc as a component, both from the outside and from
below.

Finally, to test both of the extended calculator classes, as
well as PyCalc configuration options, the script in
Example 19-24
puts up four
distinct calculator windows (this is the script run by
PyDemos).

Example 19-24. PP4E\Lang\Calculator\calculator_plusplus.py

#!/usr/local/bin/python
"""
demo all 3 calculator flavors at once
each is a distinct calculator object and window
"""
from tkinter import Tk, Button, Toplevel
import calculator, calculator_plus_ext, calculator_plus_emb
root=Tk()
calculator.CalcGui(Toplevel())
calculator.CalcGui(Toplevel(), fg='white', bg='purple')
calculator_plus_ext.CalcGuiPlus(Toplevel(), fg='gold', bg='black')
calculator_plus_emb.CalcGuiPlus(fg='black', bg='red')
Button(root, text='Quit Calcs', command=root.quit).pack()
root.mainloop()

Figure 19-8
shows the result—four independent calculators in top-level windows
within the same process. The two windows on the right represent
specialized reuses of PyCalc as a component, and the Help dialog
appears in the lower right. Although it may not be obvious in this
book, all four use different color schemes; calculator classes accept
color and font configuration options and pass them down the call chain
as
needed
.

As we learned earlier, these calculators could also be run as
independent processes by spawning command lines with the
launchmodes
module we met in
Chapter 5
. In fact, that’s how the PyGadgets
and PyDemos launcher bars run calculators, so see their code for more
details. And as always, read the code and experiment on your own for
further enlightenment; this is Python, after all.

Figure 19-8. calculator_plusplus: extend, embed, and configure!

This chapter concludes our Python language material in this
book. The next and final technical chapter of the text takes us on a
tour of techniques for integrating Python with programs written in
compiled languages like C and C++. Not everyone needs to know how to
do this, so some readers may wish to skip ahead to the book’s
conclusion in
Chapter 21
at this point.
Since most Python programmers use wrapped C libraries (even if they
don’t wrap them themselves), though, I recommend a quick pass over the
next chapter before you close the book
on this book.

Lesson 6: Have Fun

In closing, here’s a less tangible but important aspect of
Python programming. A common remark among new users is that it’s
easy to “say what you mean” in Python without getting bogged down in
complex syntax or obscure rules. It’s a programmer-friendly
language. In fact, it’s not too uncommon for Python programs to run
on the first
attempt
.

As we’ve seen in this book, there are a number of factors
behind this distinction—lack of declarations, no compile steps,
simple syntax, useful built-in objects, powerful libraries, and so
on. Python is specifically designed to optimize speed of development
(an idea we’ll expand on in
Chapter 21
). For many
users, the end result is a remarkably expressive and responsive
language, which can actually be fun to use for real work.

For instance, the calculator programs of this chapter were
initially thrown together in one afternoon, starting from vague,
incomplete goals. There was no analysis phase, no formal design, and
no official coding stage. I typed up some ideas and they worked.
Moreover, Python’s interactive nature allowed me to experiment with
new ideas and get immediate feedback. Since its initial development,
the calculator has been polished and expanded much, of course, but
the core implementation remains unchanged.

Naturally, such a laid-back programming mode doesn’t work for
every project. Sometimes more upfront design is warranted. For more
demanding tasks, Python has modular constructs and fosters systems
that can be extended in either Python or C. And a simple calculator
GUI may not be what some would call “serious” software development.
But maybe that’s part of the point, too.

[
71
]
Once again, I need to warn you about running code strings
like this if you can’t be sure they won’t cause damage. If these
strings can be entered by users you cannot trust, they will have
access to anything on the computer that the Python process has
access to. See Chapters
9
and
15
for more on security issues related to code run in GUI, Web, and
other contexts.

Chapter 20. Python/C Integration
“I Am Lost at C”

Throughout this book, our programs have all been written in Python
code. We have used interfaces to services outside Python, and we’ve coded
reusable tools in the Python language, but all our work has been done in
Python itself. Despite our programs’ scale and utility, they’ve been
Python through and through.

For many programmers and scripters, this mode makes perfect sense.
In fact, such standalone programming is one of the main ways people apply
Python. As we’ve seen, Python comes with
batteries
included
—interfaces to system tools, Internet protocols, GUIs,
data storage, and much more is already available. Moreover, most custom
tasks we’re likely to encounter have prebuilt solutions in the open source
world; the PIL system, for example, allows us to process images in tkinter
GUIs by simply running a self-installer.

But for some systems, Python’s ability to integrate with components
written in (or compatible with) the
C programming language is a crucial feature. In fact,
Python’s role as an extension and interface language in larger systems is
one of the reasons for its popularity and why it is often called a
“scripting” language in the first place. Its design supports
hybrid
systems that mix components written in a
variety of programming languages. Because different languages have
different strengths, being able to pick and choose on a
component-by-component basis is a powerful concept. You can add Python to
the mix anywhere you need a flexible and comparatively easy-to-use
language tool, without sacrificing raw speed where it matters.

Compiled languages such as C and C++ are optimized for speed of
execution
, but are complex to program—for developers,
and especially for end users who need to tailor programs. Because Python
is optimized for speed of
development
, using Python
scripts to control or customize software components written in C or C++
can yield more flexible systems, quicker execution, and faster development
modes. For example, moving selected components of a pure Python program to
C can optimize program performance. Moreover, systems designed to delegate
customizations to Python code don’t need to be shipped with full source
code and don’t require end users to learn complex or proprietary
languages.

In this last technical chapter of this book, we’re going to take a
brief look at tools for interfacing with C-language components, and
discuss both Python’s ability to be used as an embedded language tool in
other systems, and its interfaces for extending Python scripts with new
modules implemented in C-compatible languages. We’ll also briefly explore
other integration techniques that are less C specific, such as
Jython.

Notice that I said “brief” in the preceding paragraph. Because not
all Python programmers need to master this topic, because it requires
studying C language code and makefiles, and because this is the final
chapter of an already in-depth book, this chapter omits details that are
readily available in both Python’s standard manual set, and the source
code of Python itself. Instead, here we’ll take a quick look at a handful
of basic examples to help get you started in this domain, and hint at the
possibilities they imply for Python systems.

Extending and Embedding

Before we get to
any code, I want to start out by defining what we mean by
“integration” here. Although that term can be interpreted almost as
widely as “object,” our focus in this chapter is on tight
integration—where control is transferred between languages by a simple,
direct, and fast in-process function call. Although it is also possible
to link components of an application less directly using IPC and
networking tools such as sockets and pipes that we explored earlier in
the book, we are interested in this part of the book in more direct and
efficient techniques.

When you mix Python with components written in C (or other
compiled languages), either Python or C can be “on top.” Because of
that, there are two distinct integration modes and two distinct
APIs:

The extending interface

For running compiled C library code from Python
programs

The embedding interface

For running Python code from compiled C programs

Extending
generally
has three main roles: to optimize programs—recoding parts
of a program in C is a last-resort performance boost; to leverage
existing libraries—opening them up for use in Python code extends their
reach; and to allow Python programs to do things not directly supported
by the language—Python code cannot normally access devices at absolute
memory addresses, for instance, but can call C functions that do. For
example, the
NumPy package for Python is largely an instance of
extending at work: by integrating optimized numeric libraries, it turns
Python into a flexible and efficient system for numeric programming that
some compare to Matlab.

Embedding
typically
takes the role of customization—by running
user-configurable Python code, a system can be modified without shipping
or building its full source code. For instance, some programs provide a
Python customization layer that can be used to modify the program on
site by modifying Python code. Embedding is also sometimes used to route
events to Python-coded callback handlers. Python GUI toolkits, for
example, usually employ embedding in some fashion to dispatch user
events.

Figure 20-1
sketches this
traditional dual-mode integration model. In extending, control passes
from Python through a glue layer on its way to C code. In embedding, C
code processes Python objects and runs Python code by calling Python C
API functions. Because Python is “on top” in extending, it defines a
fixed integration structure, which can be automated with tools such as
SWIG—a code generator we’ll meet in this chapter, which produces glue
code required to wrap C and C++ libraries. Because Python is subordinate
in embedding, it instead provides a set of API tools which C programs
employ as needed.

Figure 20-1. Traditional integration model

In some models, things are not as clear-cut. For example, under
the
ctypes
module
discussed later, Python scripts make library calls rather than employing
C glue code. In systems such as Cython
(and its
Pyrex predecessor), things are more different
still—
C libraries are produced from
combinations of Python and C code. And in Jython and IronPython,
the model is similar, but Java and C# components replace
the C language, and the integration is largely automated. We will meet
such alternative systems later in this chapter. For now, our focus is on
traditional Python/C integration models.

This chapter introduces extending first, and then moves on to
explore the basics of embedding. Although we will study these topics in
isolation, keep in mind that many systems combine the two techniques.
For instance, embedded Python code run from C can also import and call
linked-in C extensions to interface with the enclosing application. And
in callback-based systems, C libraries initially accessed through
extending interfaces may later use embedding techniques to run Python
callback handlers
on
events
.

For example, when we created buttons with Python’s tkinter GUI
library earlier in the book, we called out to a C library through the
extending API. When our GUI’s user later clicked those buttons, the GUI
C library caught the event and routed it to our Python functions with
embedding. Although most of the details are hidden to Python code,
control jumps often and freely between languages in such systems. Python
has an open and reentrant architecture that lets you mix
languages arbitrarily.

Note

For additional Python/C integration examples beyond this book,
see the Python source code itself; its
Modules
and
Objects
directories are a wealth of code
resources. Most of the Python built-ins we have used in this book—from
simple things such as integers and strings to more advanced tools such
as files, system calls, tkinter, and DBM files—are built with the same
structures we’ll introduce here. Their utilization of integration APIs
can be studied in Python’s source code distribution as models for
extensions of your own.

In addition, Python’s
Extending and
Embedding
and
Python/C API
manuals are
reasonably complete, and provide supplemental information to the
presentation here. If you plan to do integration, you should consider
browsing these as a next step. For example, the manuals go into
additional details about C extension types, C extensions in threaded
programs, and multiple interpreters in embedded programs, which we
will largely bypass here.

BOOK: Programming Python
7.64Mb size Format: txt, pdf, ePub
ads

Other books

Her One and Only Dom by Tamsin Baker
Summer In Iron Springs by Broschinsky, Margie
Touched by Vicki Green
Beneath the Forsaken City by C. E. Laureano
Oliver's Twist by Craig Oliver
Star of the Show by Sue Bentley