100% found this document useful (1 vote)
7 views

Python for Scientists 2nd Edition John M. Stewart download

The document provides information about the book 'Python for Scientists' by John M. Stewart, including its second edition published in 2017. It covers various topics related to Python programming, scientific software, and applications in data processing. Additionally, it includes links to other related books and resources available for download.

Uploaded by

moynanseterm
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
7 views

Python for Scientists 2nd Edition John M. Stewart download

The document provides information about the book 'Python for Scientists' by John M. Stewart, including its second edition published in 2017. It covers various topics related to Python programming, scientific software, and applications in data processing. Additionally, it includes links to other related books and resources available for download.

Uploaded by

moynanseterm
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 86

Python for Scientists 2nd Edition John M.

Stewart pdf download

https://ebookgate.com/product/python-for-scientists-2nd-edition-
john-m-stewart/

Get Instant Ebook Downloads – Browse at https://ebookgate.com


Instant digital products (PDF, ePub, MOBI) available
Download now and explore formats that suit you...

Management for Engineers Scientists and Technologists 2nd


Edition John V. Chelsom

https://ebookgate.com/product/management-for-engineers-scientists-and-
technologists-2nd-edition-john-v-chelsom/

ebookgate.com

Fuzzy Mathematics An Introduction for Engineers and


Scientists 2nd Edition Professor John N. Mordeson

https://ebookgate.com/product/fuzzy-mathematics-an-introduction-for-
engineers-and-scientists-2nd-edition-professor-john-n-mordeson/

ebookgate.com

Python for Data Science For Dummies 1st Edition John Paul
Mueller

https://ebookgate.com/product/python-for-data-science-for-dummies-1st-
edition-john-paul-mueller/

ebookgate.com

Python for Bioinformatics 2nd Edition Sebastian Bassi

https://ebookgate.com/product/python-for-bioinformatics-2nd-edition-
sebastian-bassi/

ebookgate.com
Python for Everyone 2nd Edition Cay Horstmann

https://ebookgate.com/product/python-for-everyone-2nd-edition-cay-
horstmann/

ebookgate.com

Shared Care For Prostatic Diseases 2nd Edition John M


Fitzpatrick

https://ebookgate.com/product/shared-care-for-prostatic-diseases-2nd-
edition-john-m-fitzpatrick/

ebookgate.com

Introduction to Machine Learning with Python A Guide for


Data Scientists 1st Edition Andreas C. Müller

https://ebookgate.com/product/introduction-to-machine-learning-with-
python-a-guide-for-data-scientists-1st-edition-andreas-c-muller/

ebookgate.com

CISSP 7th Edition James M. Stewart

https://ebookgate.com/product/cissp-7th-edition-james-m-stewart/

ebookgate.com

Great Scientists Speak Again 2nd printing, Reprint 2020


Edition Richard M. Eakin

https://ebookgate.com/product/great-scientists-speak-again-2nd-
printing-reprint-2020-edition-richard-m-eakin/

ebookgate.com
Python for Scientists
Second Edition

J O H N M . S T E WA RT
Department of Applied Mathematics & Theoretical Physics
University of Cambridge
www.cambridge.org
Information on this title: www.cambridge.org/9781316641231
DOI: 10.1017/9781108120241

c John M. Stewart 2014, 2017

First published 2014


Second edition 2017
Printed in the United Kingdom by TJ International Ltd. Padstow Cornwall
A catalogue record for this publication is available from the British Library.
Library of Congress Cataloging-in-Publication Data
Names: Stewart, John, 1943 July 1–
Title: Python for scientists / John M. Stewart, Department of Applied, Mathematics & Theoretical
Physics, University of Cambridge.
Description: Second edition. | Cambridge, United Kingdom ; New York, NY, USA : Cambridge
University Press, [2017] | Includes bibliographical references and index.
Identifiers: LCCN 2016049298 | ISBN 9781316641231 (paperback)
Subjects: LCSH: Science–Data processing. | Python (Computer program language)
Classification: LCC Q183.9 .S865 2017 | DDC 005.13/3–dc23
LC record available at https://lccn.loc.gov/2016049298
ISBN 978-1-316-64123-1 Paperback
Additional resources for this publication at www.cambridge.org/9781316641231
Contents

Preface to the Second Edition page xiii


Preface to the First Edition xv

1 Introduction 1
1.1 Scientific Software 1
1.2 The Plan of This Book 4
1.3 Can Python Compete with Compiled Languages? 8
1.4 Limitations of This Book 9
1.5 Installing Python and Add-ons 9

2 Getting Started with IPython 11


2.1 Tab Completion 11
2.2 Introspection 12
2.3 History 14
2.4 Magic Commands 14
2.5 IPython in Action: An Extended Example 15
2.5.1 An IPython terminal workflow 17
2.5.2 An IPython notebook workflow 17

3 A Short Python Tutorial 21


3.1 Typing Python 21
3.2 Objects and Identifiers 22
3.3 Numbers 24
3.3.1 Integers 24
3.3.2 Real numbers 24
3.3.3 Boolean numbers 26
3.3.4 Complex numbers 26
3.4 Namespaces and Modules 27
3.5 Container Objects 28
3.5.1 Lists 29
3.5.2 List indexing 30
3.5.3 List slicing 30
3.5.4 List mutability 31
3.5.5 Tuples 32
3.5.6 Strings 33
3.5.7 Dictionaries 33
3.6 Python if Statements 34
3.7 Loop Constructs 35
3.7.1 The Python for loop 35
3.7.2 The Python continue statement 37
3.7.3 The Python break statement 37
3.7.4 List comprehensions 38
3.7.5 Python while loops 39
3.8 Functions 39
3.8.1 Syntax and scope 40
3.8.2 Positional arguments 43
3.8.3 Keyword arguments 43
3.8.4 Variable number of positional arguments 43
3.8.5 Variable number of keyword arguments 44
3.8.6 Python input/output functions 44
3.8.7 The Python print function 45
3.8.8 Anonymous functions 47
3.9 Introduction to Python Classes 47
3.10 The Structure of Python 50
3.11 Prime Numbers: A Worked Example 51

4 NumPy 55
4.1 One-Dimensional Arrays 57
4.1.1 Ab initio constructors 57
4.1.2 Look-alike constructors 58
4.1.3 Arithmetical operations on vectors 59
4.1.4 Ufuncs 60
4.1.5 Logical operations on vectors 62
4.2 Two-Dimensional Arrays 65
4.2.1 Broadcasting 65
4.2.2 Ab initio constructors 66
4.2.3 Look-alike constructors 68
4.2.4 Operations on arrays and ufuncs 69
4.3 Higher-Dimensional Arrays 69
4.4 Domestic Input and Output 69
4.4.1 Discursive output and input 70
4.4.2 NumPy text output and input 71
4.4.3 NumPy binary output and input 72
4.5 Foreign Input and Output 73
4.5.1 Small amounts of data 73
4.5.2 Large amounts of data 73
4.6 Miscellaneous Ufuncs 74
4.6.1 Maxima and minima 74
4.6.2 Sums and products 75
4.6.3 Simple statistics 75
4.7 Polynomials 75
4.7.1 Converting data to coefficients 76
4.7.2 Converting coefficients to data 76
4.7.3 Manipulating polynomials in coefficient form 76
4.8 Linear Algebra 76
4.8.1 Basic operations on matrices 76
4.8.2 More specialized operations on matrices 78
4.8.3 Solving linear systems of equations 79
4.9 More NumPy and Beyond 79
4.9.1 SciPy 80
4.9.2 SciKits 81

5 Two-Dimensional Graphics 82
5.1 Introduction 82
5.2 Getting Started: Simple Figures 83
5.2.1 Front-ends 83
5.2.2 Back-ends 83
5.2.3 A simple figure 84
5.2.4 Interactive controls 86
5.3 Object-Oriented Matplotlib 87
5.4 Cartesian Plots 88
5.4.1 The Matplotlib plot function 88
5.4.2 Curve styles 89
5.4.3 Marker styles 90
5.4.4 Axes, grid, labels and title 90
5.4.5 A not-so-simple example: partial sums of Fourier series 91
5.5 Polar Plots 93
5.6 Error Bars 94
5.7 Text and Annotations 95
5.8 Displaying Mathematical Formulae 96
5.8.1 Non-LATEX users 96
5.8.2 LATEX users 97
5.8.3 Alternatives for LATEX users 98
5.9 Contour Plots 98
5.10 Compound Figures 101
5.10.1 Multiple figures 101
5.10.2 Multiple plots 102
5.11 Mandelbrot Sets: A Worked Example 104

6 Multi-Dimensional Graphics 109


6.1 Introduction 109
6.1.1 Multi-dimensional data sets 109
6.2 The Reduction to Two Dimensions 109
6.3 Visualization Software 110
6.4 Example Visualization Tasks 111
6.5 Visualization of Solitary Waves 111
6.5.1 The interactivity task 112
6.5.2 The animation task 113
6.5.3 The movie task 115
6.6 Visualization of Three-Dimensional Objects 116
6.7 A Three-Dimensional Curve 118
6.7.1 Visualizing the curve with mplot3d 118
6.7.2 Visualizing the curve with mlab 120
6.8 A Simple Surface 121
6.8.1 Visualizing the simple surface with mplot3d 121
6.8.2 Visualizing the simple surface with mlab 123
6.9 A Parametrically Defined Surface 124
6.9.1 Visualizing Enneper’s surface using mplot3d 124
6.9.2 Visualizing Enneper’s surface using mlab 125
6.10 Three-Dimensional Visualization of a Julia Set 126

7 SymPy : A Computer Algebra System 129


7.1 Computer Algebra Systems 129
7.2 Symbols and Functions 130
7.3 Conversions from Python to SymPy and Vice Versa 132
7.4 Matrices and Vectors 133
7.5 Some Elementary Calculus 134
7.5.1 Differentiation 134
7.5.2 Integration 134
7.5.3 Series and limits 136
7.6 Equality, Symbolic Equality and Simplification 136
7.7 Solving Equations 138
7.7.1 Equations with one independent variable 138
7.7.2 Linear equations with more than one independent variable 139
7.7.3 More general equations 141
7.8 Solving Ordinary Differential Equations 142
7.9 Plotting from within SymPy 144

8 Ordinary Differential Equations 150


8.1 Initial Value Problems 150
8.2 Basic Concepts 150
8.3 The odeint Function 153
8.3.1 Theoretical background 153
8.3.2 The harmonic oscillator 155
8.3.3 The van der Pol oscillator 158
8.3.4 The Lorenz equations 159
8.4 Two-Point Boundary Value Problems 161
8.4.1 Introduction 161
8.4.2 Formulation of the boundary value problem 162
8.4.3 A simple example 164
8.4.4 A linear eigenvalue problem 165
8.4.5 A non-linear boundary value problem 167
8.5 Delay Differential Equations 171
8.5.1 A model equation 172
8.5.2 More general equations and their numerical solution 173
8.5.3 The logistic equation 174
8.5.4 The Mackey–Glass equation 176
8.6 Stochastic Differential Equations 179
8.6.1 The Wiener process 179
8.6.2 The Itô calculus 181
8.6.3 Itô and Stratonovich stochastic integrals 184
8.6.4 Numerical solution of stochastic differential equations 185

9 Partial Differential Equations: A Pseudospectral Approach 192


9.1 Initial Boundary Value Problems 192
9.2 Method of Lines 193
9.3 Spatial Derivatives via Finite Differencing 193
9.4 Spatial Derivatives by Spectral Techniques 194
9.5 The IVP for Spatially Periodic Problems 196
9.6 Spectral Techniques for Non-Periodic Problems 199
9.7 An Introduction to f2py 201
9.7.1 Simple examples with scalar arguments 201
9.7.2 Vector arguments 203
9.7.3 A simple example with multi-dimensional arguments 204
9.7.4 Undiscussed features of f2py 206
9.8 A Real-Life f2py Example 206
9.9 Worked Example: Burgers’ Equation 208
9.9.1 Boundary conditions: the traditional approach 208
9.9.2 Boundary conditions: the penalty approach 209

10 Case Study: Multigrid 213


10.1 The One-Dimensional Case 214
10.1.1 Linear elliptic equations 214
10.1.2 Smooth and rough modes 215
10.2 The Tools of Multigrid 215
10.2.1 Relaxation methods 215
10.2.2 Residual and error 218
10.2.3 Prolongation and restriction 219
10.3 Multigrid Schemes 220
10.3.1 The two-grid algorithm 221
10.3.2 The V-cycle scheme 222
10.3.3 The full multigrid (FMG) scheme 223
10.4 A Simple Python Multigrid Implementation 224
10.4.1 Utility functions 225
10.4.2 Smoothing functions 226
10.4.3 Multigrid functions 228

Appendix A Installing a Python Environment 235


A.1 Installing Python Packages 235
A.2 Communication with IPython Using the Jupyter Notebook 237
A.2.1 Starting and stopping the notebook 237
A.2.2 Working in the notebook 238
A.2.2.1 Entering headers 239
A.2.2.2 Entering Markdown text 239
A.2.2.3 Converting notebooks to other formats 240
A.3 Communication with IPython Using Terminal Mode 240
A.3.1 Editors for programming 240
A.3.2 The two-windows approach 241
A.3.3 Calling the editor from within IPython 242
A.3.4 Calling IPython from within the editor 242
A.4 Communication with IPython via an IDE 242
A.5 Installing Additional Packages 243

Appendix B Fortran77 Subroutines for Pseudospectral Methods 244

References 250

Hints for Using the Index 252

Index 253
Preface to the Second Edition

The motivation for writing this book, and the acknowledgements of the many who have
assisted in its production, are included in the topics of the Preface to the first edition,
which is reprinted after this one. Here I also need to adjoin thanks to the many readers
who provided constructive criticisms, most of which have been incorporated in this
revision. The purpose here is to explain why a second edition is needed. Superficially it
might appear that very little has changed, apart from a new Chapter 7 which discusses
SymPy, Python’s own computer algebra system.
There is, however, a fundamental change, which permeates most of the latest version
of this book. When the first edition was prepared, the reliable way to use the enhanced
interpreter IPython was via the traditional “terminal mode”. Preparations were under
way for an enhanced “notebook mode”, which looked then rather like the Mathemat-
ica notebook concept, except that it appeared within one’s default web browser.1 That
project has now morphed into the Jupyter notebook. The notebook allows one to con-
struct and distribute documents containing computer code (over forty languages are
supported), equations, explanatory text, figures and visualizations. Since this is also
perhaps the easiest software application for a beginner to develop Python experience,
much of the book has been rewritten for the notebook user. In particular there is now
a lightning course on how to use the notebook in Appendix A, and Chapter 2 has been
extensively rewritten to demonstrate its properties. All of the material in the book now
reflects, where appropriate, its use. For example, it allows SymPy to produce algebraic
expressions whose format is unsurpassed by other computer algebra systems.
This change also affects the areas of interactive graphics and visual animations. Their
demands are such that the standard Python two-dimensional graphics package Mat-
plotlib is having difficulty in producing platform-independent results. Indeed, because
of “improved” software upgrades, the code suggested for immediate on-screen anima-
tions in the first edition no longer works. However, the notebook concept has a subtle
solution to resolve this impasse. Recall that the notebook window is your browser win-
dow, which uses modern HTML graphics. The consequent benefits are introduced in
Chapter 6.
As a final enhancement, all but the most trivial code snippets listed in this book are
now available in electronic form, as a notebook of course, but the website includes

1 Internet access is neither required nor used.


HTML and PDF versions, see Section 1.2. The explanatory text surrounding the text is
not included. For that you have to read the book, in hard copy or ebook format!

Note added in proof:


John died shortly after the completion of the Second Edition, and is much missed by
colleagues, friends and family, especially the “Python widow”.
Preface to the First Edition

I have used computers as an aid to scientific research for over 40 years. During that
time, hardware has become cheap, fast and powerful. However, software relevant to the
working scientist has become progressively more complicated. My favourite textbooks
on Fortran90 and C++ run to 1200 and 1600 pages respectively. And then we need doc-
umentation on mathematics libraries and graphics packages. A newcomer going down
this route is going to have to invest significant amounts of time and energy in order to
write useful programmes. This has led to the emergence of “scientific packages” such
as Matlab® or Mathematica® which avoid the complications of compiled languages,
separate mathematics libraries and graphics packages. I have used them and found them
very convenient for executing the tasks envisaged by their developers. However, I also
found them very difficult to extend beyond these boundaries, and so I looked for alter-
native approaches.
Some years ago, a computer science colleague suggested that I should take a look at
Python. At that time, it was clear that Python had great potential but a very flaky imple-
mentation. It was, however, free and open-source, and was attracting what has turned
out to be a very effective army of developers. More recently, their efforts have coordi-
nated to produce a formidable package consisting of a small core language surrounded
by a wealth of add-on libraries or modules. A select group of these can and do replicate
the facilities of the conventional scientific packages. More importantly an informed, in-
telligent user of Python and its modules can carry out major projects usually entrusted
to dedicated programmers using Fortran, C etc. There is a marginal loss of execution
speed, but this is more than compensated for by the vastly telescoped development time.
The purpose of this book is to explain to working scientists the utility of this relatively
unknown resource.
Most scientists will have some computer familiarity and programming awareness,
although not necessarily with Python, and I shall take advantage of this. Therefore,
unlike many books which set out to “teach” a language, this one is not just a brisk trot
through the reference manuals. Python has many powerful but unfamiliar facets, and
these need more explanation than the familiar ones. In particular, if you encounter in
this text a reference to the “beginner” or the “unwary”, it signifies a point which is not
made clear in the documentation, and has caught out this author at least once.
The first seven chapters, plus Appendix A, cover almost everything the working sci-
entist needs to know in order to get started in using Python effectively. My editor and
some referees suggested that I should devote the second half of the book to problems in
a particular field. This would have led to a series of books, “Python for Biochemists”,
“Python for Crystallographers”, . . . , all with a common first half. Instead I have cho-
sen to cover just three topics, which, however, should be far more widely applicable in
many different fields. Chapter 8 covers four radically different types of ordinary differ-
ential equations and shows how to use the various relevant black boxes, which are often
Python wrappers around tried and trusted Fortran codes. The next chapter while os-
tensibly about pseudospectral approaches to evolutionary partial differential equations,
actually covers a topic of great utility to many scientists, namely how to reuse legacy
code, usually written in Fortran77, within Python at Fortran-like speeds, without under-
standing Fortran. The final chapter about solving very large linear systems via multigrid
is also a case history in how to use object-oriented programming meaningfully in a sci-
entific context. If readers look carefully and critically at these later chapters, they should
gain the practical expertise to handle problems in their own field.
Acknowledgments are due to the many Python developers who have produced and
documented a very useful tool, and also to the very many who have published code
snippets on the web, a great aid to the tyro, such as this author. Many of my colleagues
have offered valuable advice. Des Higham generously consented to my borrowing his
ideas for the last quarter of Chapter 8. I am especially grateful to Oliver Rinne who read
carefully and critically an early draft. At Cambridge University Press, my Production
Editor, Jessica Murphy and my Copy Editor, Anne Rix have exhibited their customary
expertise. Last but not least I thank the Department of Applied Mathematics and Theo-
retical Physics, Cambridge for continuing to offer me office space after my retirement,
which has facilitated the production of this book.

Writing a serious book is not a trivial task and so I am rather more than deeply
grateful for the near-infinite patience of Mary, the “Python-widow”, which made this
book possible!
1 Introduction

The title of this book is “Python for Scientists”, but what does that mean? The dictio-
nary defines “Python” as either (a) a non-venomous snake from Asia or Saharan Africa
or (b) a computer scripting language, and it is the second option which is intended here.
(What exactly this second definition means will be explained later.) By “scientist”, I
mean anyone who uses quantitative models either to obtain conclusions by processing
pre-collected experimental data or to model potentially observable results from a more
abstract theory, and who asks “what if?”. What if I analyse the data in a different way?
What if I change the model? Thus the term also includes economists, engineers and
mathematicians among others, as well as the usual concept of scientists. Given the vol-
ume of potential data or the complexity (non-linearity) of many theoretical models, the
use of computers to answer these questions is fast becoming mandatory.
Advances in computer hardware mean that immense amounts of data or ever more
complex models can be processed at increasingly rapid speeds. These advances also
mean reduced costs so that today virtually every scientist has access to a “personal
computer”, either a desktop work station or a laptop, and the distinction between the
two is narrowing quickly. It might seem to be a given that suitable software will also be
available so that the “what if” questions can be answered readily. However, this turns
out not always to be the case. A quick pragmatic reason is that, while there is a huge
market for hardware improvements, scientists form a very small fraction of it and so
there is little financial incentive to improve scientific software. But for scientists, this
issue is important and we need to examine it in more detail.

1.1 Scientific Software

Before we discuss what is available, it is important to note that all computer software
comes in one of two types: proprietary and open-source. The first is supplied by a com-
mercial firm. Such organizations have both to pay wages and taxes and to provide a re-
turn for their shareholders. Therefore, they have to charge real money for their products,
and, in order to protect their assets from their competitors, they do not tell the customer
how their software works. Thus, the end-users have little chance of being able to adapt
or optimize the product for their own use. Since wages and taxes are recurrent expendi-
tures, the company needs to issue frequent charged-for updates and improvements (the
Danegeld effect). Open-source software is available for free or at nominal cost (media,
2 Introduction

postage etc.). It is usually developed by computer literate individuals, often working


for universities or similar organizations, who provide the service for their colleagues. It
is distributed subject to anti-copyright licences, which give nobody the right to copy-
right it or to use it for commercial gain. Conventional economics might suggest that
the gamut of open-source software should be inferior to its proprietary counterpart, or
else the commercial organizations would lose their market. As we shall see, this is not
necessarily the case.
Next we need to differentiate between two different types of scientific software. Com-
puters operate according to a very limited and obscure set of instructions. A program-
ming language is a somewhat less limited subset of human language in which sequences
of instructions are written, usually by humans, to be read and understood by computers.
The most common languages are capable of expressing very sophisticated mathematical
concepts, albeit with a steep learning curve. Only a few language families, e.g., C and
Fortran, have been widely accepted, but they come with many different dialects, e.g.,
Fortran77, Fortran90, Ansi C, C++ etc. Compilers then translate code written by humans
into machine code which can be optimized for speed and then processed. As such, they
are rather like Formula 1 racing cars. The best of them are capable of breathtakingly fast
performance, but driving them is not intuitive and requires a great deal of training and
experience. Note that compilers need to be supplemented by libraries of software pack-
ages which implement frequently used numerical algorithms, and graphics packages
will usually be needed. Fast versatile library packages are usually expensive, although
good public domain packages are starting to appear.
A racing car is not usually the best choice for a trip to the supermarket, where speed
is not of paramount importance. Similarly, compiled languages are not always ideal for
trying out new mathematical ideas. Thus for the intended readers of this book the direct
use of compilers is likely to be unattractive, unless their use is mandatory. We there-
fore look at the other type of software, usually called “scientific packages”. Proprietary
packages include Mathematica and Matlab, and open-source equivalents include Max-
ima, Octave, R and SciLab. They all operate in a similar fashion. Each provides its own
idiosyncratic programming language in which problems are entered at a user interface.
After a coherent group of statements, often just an individual statement, has been typed,
the package writes equivalent core language code and compiles it on the fly. Thus errors
and/or results can be reported immediately back to the user. Such packages are called
“interpreters”, and older readers may remember, perhaps with mixed feelings, the BA-
SIC language. For small projects, the slow operation compared with a fully compiled
code is masked by the speed of current microprocessors, but it does become apparent
on larger jobs.
These packages are attractive for at least two reasons. The first is their ability to post-
process data. For example, suppose that x is a real variable and there exists a (possibly
unknown) function y(x). Suppose also that for an ordered set X of discrete instances of
x we have computed a corresponding set Y of instances of y. Then a command similar to
plot(X,Y) will display instantly a nicely formatted graph on the screen. Indeed, those
generated by Matlab in particular can be of publication quality. A second advantage is
the apparent ability of some of the proprietary packages to perform in addition some
1.1 Scientific Software 3

algebraic and analytic processes, and to integrate all of them with their numerical and
graphical properties. A disadvantage of all of these packages is the quirky syntax and
limited expressive ability of their command languages. Unlike the compiled languages,
it is often extremely difficult to program a process which was not envisaged by the
package authors.
The best of the proprietary packages are very easy to use with extensive on-line help
and coherent documentation, which has not yet been matched by all of the open-source
alternatives. However, a major downside of the commercial packages is the extremely
high prices charged for their licences. Most of them offer a cut down “student version”
at reduced price (but usable only while the student is in full-time education) so as to
encourage familiarity with the package. This largesse is paid for by other users.
Let us summarize the position. On the one hand, we have the traditional compiled
languages for numerics which are very general, very fast, very difficult to learn and do
not interact readily with graphical or algebraic processes. On the other, we have standard
scientific packages which are good at integrating numerics, algebra and graphics, but are
slow and limited in scope.
What properties should an ideal scientific package have? A short list might contain:
1. a mature programming language which is both easy to understand and which has
extensive expressive ability,
2. integration of algebraic, numerical and graphical functions,
3. the ability to generate numerical algorithms running with speeds within an order of
magnitude of the fastest of those generated by compiled languages,
4. a user interface with adequate on-line help, and decent documentation,
5. an extensive range of textbooks from which the curious reader can develop greater
understanding of the concepts,
6. open-source software, freely available,
7. implementation on all standard platforms, e.g., Linux, Mac OS X, Unix, Windows,
8. a concise package, and so implementable on even modest hardware.
The bad news is that no single “scientific package” quite satisfies all of these criteria.
Consider, e.g., the requirement of algebraic capability. There are two mature open-
source packages, wx-Maxima and Reduce, with significant algebraic capabilities worthy
of consideration, but Reduce fails requirement 4 and both fail criteria 3 and 5. They are,
however, extremely powerful tools in the hands of experienced users. Python, via the
add-on SymPy, see Chapter 7, almost achieves a high standard of algebraic capability.
SageMath fulfils all but the last of the criteria listed above. It is completely based on
Python and its add-ons, and also includes wx-Maxima. For further details see Chapter
7. Thus a rational strategy is to first master Python. If its, admirably few, weaknesses are
crucial for your work, then investigate SageMath. The vast majority of scientists will
find plenty of utility in Python.
In 1991, Guido van Rossum created Python as an open-source platform-independent
general purpose programming language. It is basically a very simple language sur-
rounded by an enormous library of add-on modules, including complete access to the
underlying operating system. This means that it can manage and manipulate programs
4 Introduction

built from other complete (even compiled) packages, i.e., it is a scripting language. This
versatility has ensured both its adoption by power users such as Google, and a real army
of developers. It means also that it can be a very powerful tool for the scientist. Of
course, there are other scripting languages, e.g., Java™ and Perl®, but none has the
versatility or user-base to meet criteria 3–5 above.
Ten years ago it would not have been possible to recommend Python for scientific
work. The size of the army of developers meant that there were several mutually incom-
patible add-on packages for numerical and scientific applications. Fortunately, reason
has prevailed and there is now a single numerical add-on package, NumPy, and a single
scientific one, SciPy, around which the developers have united. When the first edition
of this book was written SymPy, the Python approach to algebraic manipulation, was
still in a phase of rapid development, and so it was not included. While SymPy has yet
to achieve the capabilities of wx-Maxima and Reduce, it now handles many algebraic
tasks reliably

1.2 The Plan of This Book

The purpose of this intentionally short book is to show how easy it is for the working
scientist to implement and test non-trivial mathematical algorithms using Python. We
have quite deliberately preferred brevity and simplicity to encyclopaedic coverage in
order to get the inquisitive reader up and running as soon as possible. We aim to leave
the reader with a well-founded framework to handle many basic, and not so basic, tasks.
Obviously, most readers will need to dig further into techniques for their particular
research needs. But after reading this book, they should have a sound basis for this.
This chapter and Appendix A discuss how to set up a scientific Python environment.
While the original Python interpreter was pretty basic, its replacement IPython is so
easy to use, powerful and versatile that Chapter 2 is devoted to it, adopting a hands-on
approach.
We now describe the subsequent chapters. As each new feature is described, we try
to illustrate it first by essentially trivial examples and, where appropriate, by more ex-
tended problems. This author cannot know the mathematical sophistication of potential
readers, but in later chapters we shall presume some familiarity with basic calculus,
e.g., the Taylor series in one dimension. However, for these extended problems we shall
sketch the background needed to understand them, and suitable references for further
reading will be given.
Chapter 3 gives a brief but reasonably comprehensive survey of those aspects of the
core Python language likely to be of most interest to scientists. Python is an object-
oriented language, which lends itself naturally to object-oriented programming (OOP),
which may well be unfamiliar to most scientists. We shall adopt an extremely light
touch to this topic. We should perhaps point out that the container objects introduced
in Section 3.5 do not all have precise analogues in, say, C or Fortran. Again the brief
introduction to Python classes in Section 3.9 may be unfamiliar to users of those two
families of languages. The chapter concludes with two implementations of the sieve
1.2 The Plan of This Book 5

of Eratosthenes, which is a classical problem: enumerate all of the prime numbers1


less than a given integer n. A straightforward implementation takes 17 lines of code,
but takes inordinately long execution times once n > 105 . However, a few minutes of
thought and using already described Python features suggests a shorter 13-line program
which runs 3000 times faster and runs out of memory (on my laptop) once n > 108 .
The point of this exercise is that choosing the right approach (and Python often offers
so many) is the key to success in Python numerics.
Chapter 4 extends the core Python language via the add-on module NumPy, to give
a very efficient treatment of real and complex numbers. In the background lurk C/C++
routines to execute repetitive tasks with near-compiled-language speeds. The empha-
sis is on using structures via vectorized code rather than the traditional for-loops or
do-loops. Vectorized code sounds formidable, but, as we shall show, it is much eas-
ier to write than the old-fashioned loop-based approach. Here too we discuss the input
and output of data. First, we look at how NumPy can read and write text files, human-
readable data and binary data. Secondly, we look, very superficially, at data analysis.
We summarize also miscellaneous functions and give a brief introduction to Python’s
linear algebra capabilities. Finally, we review even more briefly a further add-on module
SciPy, which greatly extends the scope of NumPy.
Chapter 5 gives an introduction to the add-on module Matplotlib. This was inspired
by the striking graphics performance of the Matlab package and aspires to emulate or
improve on it for two-dimensional (x, y)-plots. Indeed, almost all of the figures in the
later chapters of the book were produced using Matplotlib. The original figures were
produced in colour using the relevant code snippets. The exigencies of book publish-
ing have required conversion to black, white and many shades of grey. After giving a
range of examples to illustrate its capabilities, we conclude the chapter with a slightly
more extended example, a fully functional 49-line code to compute and produce high-
definition plots of Mandelbrot sets.
The difficulties of extending the discussion to three-dimensional graphics, e.g., rep-
resentations of the surface z = z(x, y) are discussed in Chapter 6. Some aspects of this
can be handled by the Matplotlib module, but for more generality we need to invoke the
Mayavi add-on module, which is given a brief introduction together with some exam-
ple codes. If the use of such graphics is a major interest for you, then you will need to
investigate further these modules.
The final introductory chapter, Chapter 7, is an introduction to the algebraic capabil-
ities of SymPy, and, despite its limitations, you may be pleasantly surprised.
If you already have some Python experience, you can of course omit parts of these
chapters. However, their ethos is a hands-on approach. You are encouraged strongly to
try out the relevant code snippets.2 Once you have understood them, you can deepen
your understanding by modifying them. These “hacking” experiments replace the exer-
cises traditionally included in textbooks.
1 The restriction to integer arithmetic in this chapter is because our exposition of Python has yet to deal
with serious calculations involving real or complex numbers efficiently.
2 All but the shortest code snippets in this book (but not the explanatory surrounding text) are freely
available from http://www.cambridge.org/PfS2.
6 Introduction

These first chapters cover the basic tools that Python provides to enhance the scien-
tist’s computer experience. How should we proceed further?
A notable omission is that apart, from a brief discussion in Section 4.5, the vast
subject of data analysis will not be covered. There are three main reasons for this.
(a) Recently an add-on module called Pandas has appeared. This uses NumPy and Mat-
plotlib to tackle precisely this issue. It comes with comprehensive documentation,
which is described in Section 4.5.
(b) One of the authors of Pandas has written a book, McKinney (2012), which reviews
IPython, NumPy and Matplotlib and goes on to treat Pandas applications in great
detail.
(c) I do not work in this area, and so would simply have to paraphrase the sources
above.
Instead, I have chosen to concentrate on the modelling activities of scientists. One
approach would be to target problems in bioinformatics or cosmology or crystallogra-
phy or engineering or epidemiology or financial mathematics or . . . etc. Indeed, a whole
series of books with a common first half could be produced called “Python for Bioin-
formatics” etc. A less profligate and potentially more useful approach would be to write
a second half applicable to all of these fields, and many more. I am relying here on the
unity of mathematics. Problems in one field when reduced to a core dimensionless form
often look like a similarly reduced problem from another field.
This property can be illustrated by the following example. In population dynamics,
we might study a single species whose population N(T ) depends on time T . Given a
plentiful food supply, we might expect exponential growth, dN/dT = kN(T ), where the
growth constant k has dimension 1/time. However, there are usually constraints limiting
such growth. A simple model to include these is the “logistic equation”
dN
(T ) = kN(T ) (N0 − N(T )) (1.1)
dT
which allows for a stable constant population N(T ) = N0 . The biological background to
this equation is discussed in many textbooks, e.g., Murray (2002).
In (homogeneous spherically symmetric) cosmology, the density parameter Ω de-
pends on the scale factor a via
dΩ (1 + 3w)
= Ω(1 − Ω), (1.2)
da a
where w is usually taken to be a constant.
Now mathematical biology and cosmology do not have a great deal in common, but
it is easy to see that (1.1) and (1.2) represent the same equation. Suppose we scale the
independent variable T in (1.1) by t = kN0 T , which renders the new time coordinate
t dimensionless. Similarly, we introduce the dimensionless variable x = N/N0 so that
(1.1) becomes the logistic equation
dx
= x(1 − x). (1.3)
dt
In a general relativistic theory, there is no reason to prefer any one time coordinate to
1.2 The Plan of This Book 7

any other. Thus we may choose a new time coordinate t via a = et/(1+3w) , and then,
on setting x = Ω, we see that (1.2) also reduces to (1.3). Thus the same equations
can arise in a number of different fields.3 In Chapters 8–10, we have, for brevity and
simplicity, used minimal equations such as (1.3). If the minimal form for your problem
looks something like the one being treated in a code snippet, you can of course hack the
snippet to handle the original long form for your problem.
Chapter 8 looks at four types of problems involving ordinary differential equations.
We start with a very brief introduction to techniques for solving initial value problems
and then look at a number of examples, including two classic non-linear problems, the
van der Pol oscillator and the Lorenz equations. Next we survey two-point boundary
value problems and examine both a linear Sturm–Liouville eigenvalue problem and an
exercise in continuation for the non-linear Bratu problem. Problems involving delay dif-
ferential equations arise frequently in control theory and in mathematical biology, e.g.,
the logistic and Mackey–Glass equations, and a discussion of their numerical solution
is given in the next section. Finally in this chapter we look briefly at stochastic calcu-
lus and stochastic ordinary differential equations. In particular, we consider a simple
example closely linked to the Black–Scholes equation of financial mathematics.
There are two other major Python topics relevant to scientists that I would like to
introduce here. The first is the incorporation of code written in other languages. There
are two aspects of this: (a) the reuse of pre-existing legacy code, usually written in
Fortran, (b) if one’s code is being slowed down seriously by a few Python functions, as
revealed by the profiler, how do we recode the offending functions in Fortran or C? The
second topic is how can a scientific user make worthwhile use of the object-oriented
programming (OOP) features of Python?
Chapter 9 addresses the first topic via an extended example. We look first at how
pseudospectral methods can be used to attack a large number of evolution problems
governed by partial differential equations, either initial value or initial-boundary value
problems. For the sake of brevity, we look only at problems with one time and one
spatial dimension. Here, as we explain, problems with periodic spatial dependence can
be handled very efficiently using Fourier methods, but for problems which are more
general, the use of Chebyshev transforms is desirable. However, in this case there is
no satisfactory Python black box available. It turns out that the necessary tools have
already been written in legacy Fortran77 code. These are listed in Appendix B, and we
show how, with an absolutely minimal knowledge of Fortran77, we can construct ex-
tremely fast Python functions to accomplish the required tasks. Our approach relies on
the NumPy f2py tool which is included in all of the recommended Python distributions.
If you are interested in possibly reusing pre-existing legacy code, it is worthwhile study-
ing this chapter even if the specific example treated there is not the task that you have
in mind. See also Section 1.3 for other uses for f2py.
One of the most useful features of object-oriented programming (OOP) from the
point of view of the scientist is the concept of classes. Classes exist in C++ (but not
3 This example was chosen as a pedagogic example. If the initial value x(0) = x0 is specified, then the exact
solution is x(t) = x0 /[x0 + (1 − x0 )e−t ]. In the current context, x0  0. If x0  1, then all solutions tend
monotonically towards the constant solution x = 1 as t increases. See also Section 8.5.3.
8 Introduction

C) and Fortran90 and later (but not Fortran77). However, both implementations are
complicated and so are usually shunned by novice programmers. In contrast, Python’s
implementation is much simpler and more user-friendly, at the cost of omitting some of
the more arcane features of other language implementations. We give a very brief intro-
duction to the syntax in Section 3.9. However, in Chapter 10 we present a much more
realistic example: the use of multigrid to solve elliptic partial differential equations in
an arbitrary number of dimensions, although for brevity the example code is for two di-
mensions. Multigrid is by now a classical problem which is best defined recursively, and
we devote a few pages to describing it, at least in outline. The pre-existing legacy code
is quite complicated because the authors needed to simulate recursion in languages,
e.g., Fortran77, which do not support recursion. Of course, we could implement this
code using the f2py tool outlined in Chapter 9. Instead, we have chosen to use Python
classes and recursion to construct a simple clear multigrid code. As a concrete example,
we use the sample problem from the corresponding chapter in Press et al. (2007) so
that the inquisitive reader can compare the non-recursive and OOP approaches. If you
have no particular interest in multigrid, but do have problems involving linked math-
ematical structures, and such problems arise often in, e.g., bioinformatics, chemistry,
epidemiology and solid-state physics among others, then you should certainly peruse
this final chapter to see how, if you state reasonably mathematically precisely what your
problems are, then it is easy to construct Python code to solve them.

1.3 Can Python Compete with Compiled Languages?

The most common criticism of Python and the scientific software packages is that they
are far too slow, in comparison with compiled code, when handling complicated realistic
problems. The speed-hungry reader might like to look at a recent study4 of a straight-
forward “number-crunching” problem treated by various methods. Although the figures
given in the final section refer to one particular problem treated on a single processor,
they do give a “ball park” impression of performance. As a benchmark, they use the
speed of a fully compiled C++ program which solves the problem. A Python solution
using the technique of Chapter 3, i.e., core Python, is about 700 times slower. Once
you use the floating-point module NumPy and the techniques described in Chapter 4
the code is only about ten times slower, and the Matlab performance is estimated to be
similar. However, as the study indicates, there are a number of ways to speed up Python
to about 80% of the C++ performance. Some of these are very rewarding exercises in
computer science.
One in particular, though, is extremely useful for scientists: the f2py tool. This is
discussed in detail in Chapter 9, where we show how we can reuse legacy Fortran code.
It can also be used to access standard Fortran libraries, e.g., the NAG libraries.5 Yet
another use is to speed up NumPy code and so improve performance! To see how this
works, suppose we have developed a program such as those outlined in the later sections
4 See http://wiki.scipy.org/PerformancePython.
5 See, e.g., http://www.nag.co.uk/doc/TechRep/pdf/TR1_08.pdf.
1.4 Limitations of This Book 9

of the book, which uses a large number of functions, each of which carries out a simple
task. The program works correctly, but is unacceptably slow. Note that getting detailed
timing data for Python code is straightforward. Python includes a “profiler” which can
be run on the working program. This outputs a detailed list of the functions ordered by
the time spent executing them. It is very easy to use, and this is described in Section 2.5.
Usually, there are one or two functions which take a very long time to execute simple
algorithms.
This is where f2py comes into its own. Because the functions are simple, even begin-
ners can soon create equivalent code in, say, Fortran77 or Ansi C. Also, because what
we are coding is simple, there is no need for the elaborate (and laborious to learn) fea-
tures of, say, Fortran95 or C++. Next we encapsulate the code in Python functions using
the f2py tool, and slot them into the Python program. With a little experience, we can
achieve speeds comparable to that of a program written fully in, say, Fortran95.

1.4 Limitations of This Book

A comprehensive treatment of Python and its various branches would occupy several
large volumes and would be out of date before it reached the bookshops. This book
is intended to offer the reader a starting point which is sufficient to be able to use the
fundamental add-on packages. Once the reader has a little experience with what Python
can do, it is time to explore further those areas which interest the reader.
I am conscious of the fact that I have not even mentioned vitally important concepts,
e.g., finite-volume methods for hyperbolic problems,6 parallel programming and real-
time graphics to name but a few areas in which Python is very useful. There is a very
large army of Python developers working at the frontiers of research, and their endeav-
ours are readily accessed via the internet. Please think of this little book as a transport
facility towards the front line.

1.5 Installing Python and Add-ons

Users of Matlab and Mathematica are used to a customized Integrated Development


Environment (IDE). From the start-up screen, you can investigate code, write, edit and
save segments using the built-in editor, and run actual programs. Since the operating
systems Mac OS X and most flavours of Linux include a version of core Python as a
matter of course, many computer officers and other seasoned hackers will tell you that
it is simple to install the additional packages, and you can be up and coding within the
hour, thus ameliorating the difference.
Unfortunately, the pundits are wrong. The Python system being advocated in this
book runs the language to its extreme limits, and all of the add-ons must be compatible
with each other. Like many others, this author has endured hours of frustration trying to
6 The well-regarded Clawpack package http://depts.washington.edu/clawpack, which is
Fortran-based, has switched from Matlab to Python Matplotlib for its graphics support.
10 Introduction

pursue the pundits’ policy. Please save your energy, sanity etc., and read Appendix A,
which I have quite deliberately targeted at novices, for the obvious reason!
Admittedly, there is an amount, albeit slight and low-level, of hassle involved here.
So what’s the payoff? Well, if you follow the routes suggested in Appendix A, you
should end up with a system which works seamlessly. While it is true that the original
Python interpreter was not terribly user-friendly, which caused all of the established IDE
purveyors to offer a “Python mode”, the need which they purported to supply has been
overtaken by the enhanced interpreter IPython. Indeed, in its latest versions IPython
hopes to surpass the facilities offered by Matlab, Mathematica and the Python-related
features of commercial IDEs. In particular, it allows you to use your favourite editor,
not theirs, and to tailor its commands to your needs, as explained in Appendix A and
Chapter 2.
2 Getting Started with IPython

This sounds like software produced by Apple®, but it is in fact a Python interpreter on
steroids. It has been designed and written by scientists with the aim of offering very fast
exploration and construction of code with minimal typing effort, and offering appro-
priate, even maximal, on-screen help when required. Documentation and much more is
available on the website.1 This chapter is a brief introduction to the essentials of using
IPython. A more extended discursive treatment can be found in, e.g., Rossant (2015).
In this chapter we shall concentrate on notebook and terminal modes, and we assume
that the reader has set up the environments as described in Sections A.2 and A.3. Before
we get to realistic examples, I must ask for the impatient reader’s forbearance. Tab com-
pletion, Section 2.1, is an unusual but effective method for minimizing key-strokes, and
the introspection feature, Section 2.2 shows how to generate relevant inline information
quickly, without pausing to consult the manual.

2.1 Tab Completion

While using the IPython interpreter, tab completion is always present. This means that,
whenever we start typing a Python-related name on a line or in a cell, we can pause
and press the tab key, to see a list of names valid in this context, which agree with the
characters already typed.
As an example, suppose we need to type import matplotlib.2 Typing itab re-
veals 15 possible completions. By inspection, only one of them has second letter m, so
that imtab will complete to import. Augmenting this to import mtab shows 30 pos-
sibilities, and by inspection we see that we need to complete the command by import
matptab to complete the desired line.
That example was somewhat contrived. Here is a more compulsive reason for using
tab completion. When developing code, we tend, lazily, to use short names for vari-
ables, functions etc. (In early versions of Fortran, we were indeed restricted to six or
eight characters, but nowadays the length can be arbitrary.) Short names are not always
meaningful ones, and the danger is that if we revisit the code in six months, the intent of
the code may no longer be self-evident. By using meaningful names of whatever length

1 It can be found at www.ipython.org.


2 matplotlib is essential to scientific graphics and forms the main topic of Chapter 5.
12 Getting Started with IPython

is needed, we can avoid this trap. Because of tab completion, the full long name only
need be typed once.

2.2 Introspection

IPython has the ability to inspect just about any Python construct, including itself, and
to report whatever information its developers have chosen to make available. This fa-
cility is called introspection. It is accessed by the single character ?. The easiest way to
understand it is to use it, so you are recommended to fire up the interpreter.
Which mode, terminal or notebook, should one use? Beginners should start with ter-
minal mode, as described in Section A.3, thus removing one level of complexity. This
persists throughout this chapter until Section 2.5, where the code snippets are extremely
short. If you choose to use terminal mode, type ipython followed by a ret on the com-
mand line. IPython will respond with quite a lengthy header, followed by an input line
labelled In [1]:. Now that you are in IPython, you can try out introspection by typing
? (followed by ret) on the input line. (Note that within IPython terminal mode the ret
actually executes the command in the current line.) IPython responds by issuing in pager
mode3 a summary of all of the facilities available. If you exit this, then the command
quickref (hint: use tab completion) gives a more concise version. Very careful study
of both documents is highly recommended.
IPython notebook users need to use slightly different commands. After invoking the
notebook, see Section A.2.2 for details, they will be confronted with an unnumbered
single-line blank cell. Now they can try out introspection by typing ? on the input line.
Typing ret at this point merely adds a new line to the cell. In order to execute the
command(s) in the cell one needs to add either shift+ret (which also creates a new cell
below the current one), or ctl+ret which just executes the command(s). The output, the
lengthy facilities summary, appears in a scrollable window at the bottom of the screen.
It can be killed by clicking on the x-button at the top right of the window. The command
quickref (hint: use tab completion) followed by ctl-ret gives a more concise version.
Again very careful study of both documents is highly recommended.
However, scientists are impatient folk, and the purpose of this chapter is to get them
up and running with the most useful features. Therefore, we need to type in some Python
code, which newcomers will have to take on trust until they have mastered Chapters 3
and 4. Again, depending on whether you are operating in notebook or console mode,
the procedures differ slightly.
Notebook users should type each boxed line or boxed code snippet into a cell. They
can then execute the code via ctl+ret or shift+ret. Readers using terminal mode
3 This is based on the Unix less facility. To use it effectively you need know only four commands:

• space gives the next screen,


• b gives the previous screen,
• h gives the help screen, which includes less frequently used commands,
• q quits.
2.2 Introspection 13

should type in, line by line, boxed lines or code snippets and enter each line separately
using the ret key.
For example, please type in

a=3
b=2.7
c=12 + 5j
s=’Hello World!’
L=[a, b, c, s, 77.77]

The first two lines mean that a refers to an integer and


√ b to a float (floating-point num-
ber). Python uses√ the engineers’ convention whereby −1 = j. (Mathematicians would
have preferred −1 = i.) Then c refers to a complex number.4 Typing each of a, b and
c on a line5 by itself and executing it, reveals the value of the object to which the identi-
fier refers. Note that there is a useful shortcut to display multiple values – try a, b, c
on a single line. Next try c? on a line by itself. This confirms that c does indeed refer
to a complex number, shows how it will be displayed and points out that another way
of creating it would have been c=complex(12,5). Next try c. immediately followed
by tab. The interpreter will immediately offer three possible completions. What do they
mean? Here it is almost obvious, but try c.real?. (Using tab completion, you don’t
need to type eal.) This reveals that c.real is a float with the value 12, i.e., the real
part of the complex number. The newcomer might like to check out c.imag. Next try
out c.conjugate?. (Again only five keystrokes plus return are needed!) This reveals
that c.conjugate is a function, to be used, e.g., as cc = c.conjugate().
The notation here might seem rather strange to users of say Fortran or C, where
real(c) or conjugate(c) might have been expected. The change in syntax comes
about because Python is an object-oriented language. The object here is 12+5j, referred
to as c. Then c.real is an enquiry as to the value of a component of the object. It
changes nothing. However, c.conjugate() either alters the object or, as here, creates
a new one, and is hence a function. This notation is uniform for all objects, and is
discussed in more detail in Section 3.10.
Returning to the snippet, typing s by itself on a line prints a string. We can confirm
this by the line s?, and s. followed by a tab reveals 38 possible completions associated
with string objects. The reader should use introspection to reveal what some of them do.
Similarly, L.? shows that L is a list object with nine available completions. Do try a few
of them out! As a general rule, the use of introspection and tab completion anywhere
in Python code should generate focused documentation. There is a further introspection
command ?? which, where appropriate, will reveal the original source code of a func-
tion, and an example will be given later in Section 2.5. (The object functions we have
so far encountered are built-in, and were not coded in Python!)

4 Note that in the code snippet there is no multiplication sign (*) between 5 and j.
5 For the sake of brevity, we shall not distinguish between a line in terminal mode and a one-line cell in
notebook mode.
14 Getting Started with IPython

2.3 History

If you look at the output from the code in the previous section, you will see that IPython
employs a history mechanism which is very similar to that in Mathematica notebooks.
Input lines are labelled In[1], In[2], . . . , and if input In[n] produces any output, it
is labelled Out[n]. As a convenience, the past three input lines/cells are available as
_i, _ii and _iii, and the corresponding output lines/cells are available as _, __ and
___. In practice though, you can insert the content of a previous input line/cell into the
current one by navigating using ↑ (or ctl-p) and ↓ (or ctl-n), and this is perhaps the
most common usage. Unusually, but conveniently, history persists in terminal mode. If
you close down IPython (using exit) and then restart it, the history of the previous
session is still available via the arrow keys. There are many more elaborate things you
can do with the history mechanism, try the command history?.

2.4 Magic Commands

The IPython interpreter expects to receive valid Python commands. However, it is very
convenient to be able to type commands which control either the behaviour of IPython
or that of the underlying operating system. Such commands, which coexist with Python
ones, are called magic commands. A very long very detailed description can be found
by typing %magic in the interpreter, and a compact list of available commands is given
by typing %lsmagic. (Do not forget tab completion!) Note that there are two types of
magic, line magic, prefixed by %, and cell magic, prefixed by %%. The latter is relevant
only to notebook mode. You can get very helpful documentation on each command by
using introspection.
Let us start by considering system commands. A harmless example is pwd, which
comes from the Unix operating system where it just prints the name of the current
directory (print working directory) and exits. There are usually three ways to achieve
this in the IPython window. You should try out the following commands.

!pwd

Nothing in Python starts with a “!”, and IPython interprets this as the Unix shell com-
mand pwd, and produces the ASCII answer.

%pwd

Nothing in Python starts with a “%”, and IPython treats this as a line magic command,
interpreting it as the shell command. The u indicates that the string is encoded in Uni-
code, which enables a rich variety of outputs. Unicode is mentioned briefly in Section
A.3.1.

pwd
2.5 IPython in Action: An Extended Example 15

Here is a subtle, but useful, feature. For line magic commands, the % prefix is not al-
ways necessary, see the discussion of %automagic below. The interpreter sees no other
meaning for pwd and so treats it as %pwd.
pwd=’hoho’

pwd

Now pwd is assigned to a string and the magic is switched off.


%pwd

Here the intent is unambiguous.


del pwd

pwd

Now that pwd has no other assignment, it works as a line magic command.
%automagic?

If %automagic is on, as it is by default, the single per cent sign (%) which starts all line
magic commands, can be omitted. This is a great convenience, provided one remembers
that one is dealing with a magic command.
Magic cell commands start with two mandatory per cent signs. They operate on entire
cells, and can be extremely useful, see, e.g., the next section.

2.5 IPython in Action: An Extended Example

For the rest of this chapter we present the first part of an extended example, in order to
show the effectiveness of magic commands. The second part is the example, in Section
3.9, where we consider how to implement arbitrary precision real arithmetic via frac-
tions. There is an issue with fractions, e.g., 3/7 and 24/56 are usually regarded as the
same number. Thus there is a problem here, to determine the “highest common factor”
of two integers a and b, or, as mathematicians are wont to say, their “greatest common
divisor” (GCD), which can be used to produce a canonical form for the fraction a/b.
(By inspection of factors, the GCD of 24 and 56 is 8, which implies 24/56 = 3/7 and no
further reduction of the latter is possible.) Inspection of factors is not easily automated,
and a little research, e.g., on the web, reveals Euclid’s algorithm. To express this con-
cisely, we need a piece of jargon. Suppose a and b are integers. Consider long division
of a by b. The remainder is called a mod b, e.g., 13 mod 5 = 3, and 5 mod 13 = 5. Now
denote the GCD of a and b by gcd(a, b). Euclid’s algorithm is most easily described
recursively via
gcd(a, 0) = a, gcd(a, b) = gcd(b, a mod b), (b  0). (2.1)
16 Getting Started with IPython

Try evaluating by hand gcd(56, 24) according to this recipe. It’s very fast! It can be
shown that the most laborious case arises when a and b are consecutive Fibonacci num-
bers, so they would be useful for a test case. The Fibonacci numbers Fn are defined
recursively via
F0 = 0, F1 = 1, Fn = Fn−1 + Fn−2 , n  2. (2.2)
The sequence begins 0, 1, 1, 2, 3, 5, 8, . . ..
How do we implement both Euclid’s algorithm and Fibonacci numbers efficiently
and speedily in Python? We start with the Fibonacci task because it looks to be more
straightforward.
In order to get started with mastering IPython, the novice reader is asked to take
on trust the next two code snippets. A partial explanation is offered here, but all of
the features will be explained more thoroughly in Chapter 3. However, an important
point needs to be made here. Every programming language needs subsidiary blocks of
code, e.g., the contents of functions or do-loops. Most delineate them by some form of
bracketing, but Python relies exclusively on indentation. All blocks of code must have
the same indentation. The need for a sub-block is usually indicated by a colon (:). A
sub-block is further indented (four spaces is the conventional choice), and the end of
the sub-block is indicated by the cancellation of this extra indentation. IPython and all
Python-aware editors will handle this automatically. Three examples are given below.
The novice reader should try to understand, perhaps roughly, what is going on, before
we move on to consider possible workflows to execute the snippets.
1 # File: fib.py Fibonacci numbers
2

3 """ Module fib: Fibonacci numbers.


4 Contains one function fib(n).
5 """
6

7 def fib(n):
8 """ Returns n’th Fibonacci number. """
9 a,b=0,1
10 for i in range(n):
11 a,b=b,a+b
12 return a
13

14 ####################################################
15 if __name__ == "__main__":
16 for i in range(1001):
17 print "fib(",i,") = ",fib(i)

The details of Python syntax are explained in Chapter 3. For the time being, note that
lines starting with a hash (#), e.g., lines 1 and 14, denote comments. Also lines 3–5
define a docstring, whose purpose will be explained shortly. Lines 7–12 define a Python
function. Note the point made above that every colon (:) demands an indentation. Line 7
2.5 IPython in Action: An Extended Example 17

is the function declaration. Line 8 is the function docstring, again soon to be explained.
Line 9 introduces identifiers a and b, which are local to this function, and refer initially
to the values 0 and 1 respectively. Next examine line 11, ignoring for the moment its in-
dentation. Here a is set to refer to the value that b originally referred to. Simultaneously,
b is set to refer to the sum of values originally referred to by a and b. Clearly, lines 9
and 11 replicate the calculations implicit in (2.2). Now line 10 introduces a for-loop or
do-loop, explained in Section 3.7.1, which extends over line 11. Here range(n) gener-
ates a dummy list with n elements, [0, 1, . . . , n − 1], and so line 11 is executed precisely
n times. Finally, line 12 exits the function with the return value set to that referred to
finally by a.
Naturally, we need to provide a test suite to demonstrate that this function behaves as
intended. Line 14 is simply a comment. Line 15 will be explained soon. (When typing it,
note that there are four pairs of underscores.) Because it is an if statement terminated by
a colon, all subsequent lines need to be indented. We have already seen the idea behind
line 16. We repeat line 17 precisely 1001 times with i = 0, 1, 2, . . . , 1000. It prints a
string with four characters, the value of i, another string with four characters, and the
value of fib(i).
We now present two possible workflows for creating and using this snippet.

2.5.1 An IPython terminal workflow


Using your chosen editor first create a file fib.py in the directory where IPython is
running, which holds the content of the code snippet, and then save it. Then, within the
IPython window, issue the (magic) command run fib. If your creation was syntacti-
cally correct, the response will be 1001 lines of Fibonacci values. If not, the response
will indicate the first error encountered. Returning to the editor window, correct and
save the source. Then try the run fib command again. (Beginners must expect to go
through this cycle several times, but it is quick!)

2.5.2 An IPython notebook workflow


Open a new cell and type the code snippet into it. It is then prudent to save the notebook
(esc followed by s). Next run the cell, using ctl+return. If your creation was syntac-
tically correct, the response will be 1001 lines of Fibonacci values. If not, the response
will indicate the first error encountered. Return to the cell, correct it and run the cell
again (Beginners must expect to go through this cycle several times, but it is quick!)
Once you are happy with the program, return to the cell, and insert right at the front the
cell magic command
%%writefile fib.py

Now run the cell again. This write the cell content to the file fib.py in the current
directory, or overwrites that file if it already existed.
Once the program has been verified, we can ask how fast is it? Run the program again
but with the enhanced magic command run -t fib and IPython will produce timing
18 Getting Started with IPython

data. On my machine, the “User time” is 0.05 s, but the “Wall time” is 0.6 s. Clearly,
the discrepancy reflects the very large number of characters printed to the screen. To
verify this, modify the snippet as follows. Comment out the print statement in line 17 by
inserting a hash (#) character at the start of the line. Add a new line 18: fib(i), being
careful to get the indentation correct. (This evaluates the function, but does nothing with
the value.) Now run the program again. On my machine it takes 0.03 s, showing that
fib(i) is fast, but printing is not. (Don’t forget to comment out line 18, and uncomment
in line 17!)
We still need to explain the docstrings in lines 3–5 and 8, and the weird line 15. Close
down IPython (in terminal mode, use exit) and then reopen a fresh version. Type the
single line import fib, which reflects the core of the filename. The tail .py is not
needed. We have imported an object fib. What is it? Introspection suggests the com-
mand fib?, and IPython’s response is to print the docstring from lines 3–5 of the snip-
pet. This suggests that we find out more about the function fib.fib, so try fib.fib?,
and we are returned the docstring from line 8. The purpose of docstrings, which are
messages enclosed in pairs of triple double-quotes, is to offer online documentation to
other users and, just as importantly, you in a few days time! However, introspection has
a further trick up its sleeve. Try fib.fib?? and you will receive a listing of the source
code for this function!
You should have noticed that import fib did not list the first 1001 Fibonacci num-
bers. Had we instead, in a separate session, issued the command run fib, they would
have been printed! Line 15 of the snippet detects whether the file fib.py is being im-
ported or run, and responds accordingly without or with the test suite. How it does this
is explained in Section 3.4.
Now we return to our original task, which was to implement the gcd function implicit
in equation (2.1). Once we recognize that (i) Python has no problem with recursion, and
(ii) a mod b is implemented as a%b, then a minimal thought solution suggests itself, as
in the following snippet. (Ignore for the time being lines 14–18.)

1 # File gcd.py Implementing the GCD Euclidean algorithm.


2

3 """ Module gcd: contains two implementations of the Euclid


4 GCD algorithm, gcdr and gcd.
5 """
6

7 def gcdr(a,b):
8 """ Euclidean algorithm, recursive vers., returns GCD. """
9 if b==0:
10 return a
11 else:
12 return gcdr(b,a%b)
13

14 def gcd(a,b):
15 """ Euclidean algorithm, non-recursive vers., returns GCD. """
2.5 IPython in Action: An Extended Example 19

16 while b:
17 a,b=b,a%b
18 return a
19

20 ##########################################################
21 if __name__ == "__main__":
22 import fib
23

24 for i in range(963):
25 print i, ’ ’, gcd(fib.fib(i),fib.fib(i+1))

The only real novelty in this snippet is the import fib statement in line 22, and we
have already discussed its effect above. The number of times the loop in lines 24 and 25
is executed is crucial. As printed, this snippet should run in a fraction of a second. Now
change the parameter 963 in line 24 to 964, save the file, and apply run gcd again. You
should find that the output appears to be in an infinite loop, but be patient. Eventually,
the process will terminate with an error statement that the maximum recursion depth
has been exceeded. While Python allows recursion, there is a limit on the number of
self-calls that can be made.
This limitation may or may not be a problem for you. But it is worth a few moments
thought to decide whether we could implement Euclid’s algorithm (2.1) without using
recursion. I offer one possible solution in the function gcd implemented in lines 14–18
of the snippet. Lines 16 and 17 define a while loop, note the colon terminating line 16.
Between while and the colon, Python expects an expression which evaluates to one of
the Boolean values True or False. As long as True is found, the loop executes line 17,
and then retests the expression. If the test produces False, then the loop terminates
and control passes to the next statement, line 18. In the expected context, b will always
be an integer, so how can an integer take a Boolean value? The answer is remarkably
simple. The integer value zero is always coerced to False, but all non-zero values
coerce to True. Thus the loop terminates when b becomes zero, and then the function
returns the value a. This is the first clause of (2.1). The transformation in line 17 is the
second clause, so this function implements the algorithm. It is shorter than the recursive
function, can be called an arbitrary number of times and, as we shall see, runs faster.
So was the expenditure of thought worthwhile? Using the run command, we can
obtain revealing statistics. First, edit the snippet to make 963 loops with the gcdr func-
tion, and save it. Now invoke run -t gcd to obtain the time spent. On my machine, the
“User time” is 0.31 s. Yours will vary, but it is relative timings that matter. The “Wall
time” reflects the display overhead and is not relevant here. Next invoke run -p gcd,
which invokes the Python profiler. Although you would need to read the documenta-
tion to understand every facet of the resulting display, a little scientific intuition can be
very useful. This shows that there were 963 direct calls (as expected) of the function
gcdr, within a total of 464,167 actual calls. The actual time spent within this func-
tion was 0.237 s. Next there were 1926 calls (as expected) of the function fib, and the
time expended was 0.084 s. Note that these timings cannot be compared with the older
20 Getting Started with IPython

run -t gcd ones, because the newer ones include the profiler overhead, which is sig-
nificant here. However, we can conclude that about 74% of the time was spent in the
function gcdr.
Next we need to repeat the exercise for the gcd function. Amend line 25 of the snippet
to replace gcdr by gcd and resave the file. Now run -t gcd to get a “User time” of
0.20 s. The other command run -p gcd reveals that the 1926 calls of function fib
took 0.090 s. However, the function gcd was called only 993 times (as expected), which
occupied 0.087 s. Thus gcd occupied about 49% of the time taken. Very approximately,
these relative timings factor out the profiler overhead. Now 74% of the 0.31 s timing
for the recursive version is 0.23 s, while 49% of the 0.20 s time for the non-recursive
version is 0.098 s. Thus the expenditure of thought has produced a shortened code which
runs in 43% of the time of the “thoughtless code”!
There are two points which need to be gleaned from this example.
1. The IPython magic command run or %run is the Python workhorse. You do need,
via introspection, to study its docstring. Look also at the variants %run -t and
%run -p. It is also worthwhile introspecting %timeit at this stage.
2. You will see much in the literature about methods for “speeding up” Python. These
are often very clever pieces of software engineering. But none are as effective as
human ingenuity!
3 A Short Python Tutorial

Although Python is a small language, it is a very rich one. It is very tempting, when
writing a textbook, to spell out all of the ramifications, concept by concept. The obvious
example is the introductory tutorial from the originator of Python, Guido van Rossum.
This is available in electronic form as the tutorial in your Python documentation or
on-line1 or as hard copy (van Rossum and Drake Jr. (2011)). It is relatively terse at
150 printed pages, and does not mention NumPy. My favourite textbook, Lutz (2013),
runs to over 1500 pages, a marathon learning curve, and mentions NumPy only in pass-
ing. It is excellent at explaining the features in detail, but is too expansive for a first
course in Python. A similar criticism can be applied to two books with a more scientific
orientation, Langtangen (2009) and Langtangen (2014), both around 800 pages, with a
significant overlap between them. I recommend these various books among many others
for reference, but not for learning the language.
Very few people would learn a foreign language by first mastering a grammar text-
book and then memorizing a dictionary. Most start with a few rudiments of grammar
and a tiny vocabulary. Then by practice they gradually extend their range of constructs
and working vocabulary. This allows them to comprehend and speak the language very
quickly, and it is the approach to learning Python that is being adopted here. The dis-
advantage is that the grammar and vocabulary are diffused throughout the learning pro-
cess, but this is ameliorated by the existence of textbooks, such as those cited in the first
paragraph.

3.1 Typing Python

Although the narrative can simply be read, it is extremely helpful to have the IPython
terminal to hand, so that you can try out the code samples. For longer code snippets,
e.g., those in Sections 3.9 and 3.11, it is advisable to use either notebook mode, or
terminal mode together with an editor, so that you can save the code. Your choices are
described in Sections A.2 and A.3 of Appendix A. After trying out the code snippets,
you are strongly encouraged to try out your own experiments in the interpreter.
Every programming language includes blocks of code, which consist of one or more
lines of code forming a syntactic whole. Python uses rather fewer parentheses () and
braces {} than other languages, and instead uses indentation as a tool for formatting
1 It is available at http://docs.python.org/2/tutorial.
22 A Short Python Tutorial

blocks. After any line ending in a colon, :, a block is required, and it is differentiated
from the surrounding code by being consistently indented. Although the amount is not
specified, the unofficial standard is four spaces. IPython and any Python-aware text
editor will do this automatically. To revert to the original indentation level, use the
ret key to enter a totally empty line. Removing braces improves readability, but the
disadvantage is that each line in a block must have the same indentation as the one
before, or a syntax error will occur.
Python allows two forms of comments. A hash symbol, #, indicates that the rest of
the current line is a comment, or more precisely a “tweet”. A “documentation string” or
docstring can run over many lines and include any printable character. It is delimited by
a pair of triple quotes, e.g.,

""" This is a very short docstring. """

For completeness, we note that we may place several statements on the same line, pro-
vided we separate them with semicolons, but we should think about readability. Long
statements can be broken up with the continuation symbol ‘\’. More usefully, if a state-
ment includes a pair of brackets, (), we can split the line at any point between them
without the need for the continuation symbol. Here are simple examples.

a=4; b=5.5; c=1.5+2j; d=’a’


e=6.0*a-b*b+\
c**(a+b+c)
f=6.0*a-b*b+c**(
a+b+c)
a, b, c, d, e, f

3.2 Objects and Identifiers

Python deals exclusively with objects and identifiers. An object may be thought of as a
region of computer memory containing both some data and information associated with
those data. For a simple object, this information consists of its type and its identity,2 i.e.,
the location in memory, which is of course machine dependent. The identity is therefore
of no interest for most users. They need a machine-independent method for accessing
objects. This is provided by an identifier, a label which can be attached to objects. It is
made up of one or more characters. The first must be a letter or underscore, and any sub-
sequent characters must be digits, letters or underscores. Identifiers are case-sensitive:
x and X are different identifiers. (Identifiers which have leading and/or trailing under-
scores have specialized uses, and should be avoided by the beginner.) We must avoid
using predefined words, e.g., list, and should always try to use meaningful identifiers.
However, the choice among, say xnew, x_new and xNew is a matter of taste. Consider
2 An unfortunate choice of name, not to be confused with the about-to-be-defined identifiers.
3.2 Objects and Identifiers 23

  

     

  





  

Figure 3.1 A schematic representation of assignments in Python. After the first command
p=3.14, the float object 3.14 is created and identifier p is assigned to it. Here the object is
depicted by its identity, a large number, its address in the memory of my computer (highly
machine-dependent) where the data are stored, and the type. The second command q=p assigns
identifier q to the same object. The third command p=’pi’ assigns p to a new “string” object,
leaving q pointing to the original float object.

the following code, which makes most sense if typed in, line-by-line, in the terminal
window.

1 p=3.14
2 p
3 q=p
4 p=’pi’
5 p
6 q

Note that we never declared the type of the object referred to by the identifier p. We
would have had to declare p to be of type “double” in C and “real*8” in Fortran. This is
no accident or oversight. A fundamental feature of Python is that the type belongs to
the object, not to the identifier.3
Next, in line 3, we set q=p. The right-hand side is replaced by whatever object p
pointed to, and q is a new identifier which points to this object, see Figure 3.1. No
equality of identifiers q and p is implied here! Notice that, in line 4, we reassign the
identifier p to a “string” object. However, the original float object is still pointed to by
the identifier q, see Figure 3.1, and this is confirmed by the output of lines 5 and 6. Sup-
pose we were to reassign the identifier q. Then, unless in the interim another identifier
had been assigned to q, the original “float” object would have no identifier assigned to
it and so becomes inaccessible to the programmer. Python will detect this automatically
and silently free up the computer memory, a process known as garbage collection.
3 The curious can find the type of an object with identifier p with the command type(p) and its identity
with id(p).
24 A Short Python Tutorial

Because of its importance in what follows we emphasize the point that the basic
building block in Python is the assignment operation, which despite appearances has
nothing to do with equality. In pseudocode,
<identifier>=<object>

which will appear over and over again. As we have already stated earlier, the type of
an object “belongs” to the object and not to any identifier assigned to it. Henceforth we
shall try to be less pedantic!
Since we have introduced a “float”, albeit informally, we turn next to a simple class
of objects.

3.3 Numbers

Python contains three simple types of number objects, and we introduce a fourth, not so
simple, one.

3.3.1 Integers
Python refers to integers as ints. Early versions supported integers only in the range
[−231 , 231 − 1], but in recent versions the range is considerably larger and is now limited
only by the availability of memory.
The usual operations of addition (+), subtraction (−) and multiplication (∗) are of
course available. There is a slight problem with division, for though p and q may be
integers, p/q need not. We may assume without loss of generality that q > 0, in which
case there exist unique integers m and n with
p = mq + n, where 0  n < q.
Then integer division in Python is defined by p//q, which returns m. The remainder n
is available as p%q. Exponentiation pq is also available as p**q, and can produce a real
number if q < 0.

3.3.2 Real numbers


Floating-point numbers are readily available as floats. In most installations, the default
will be approximately 16 digits of precision for floats in the range (10−308 , 10308 ). These
correspond to doubles in the C-family of languages and real*8 in the Fortran family.
The notation for float constants is standard, e.g.,
-3.14, -314e-2, -314.0e-2, -0.00314E3

all represent the same float.


The usual arithmetic rules for addition, subtraction, multiplication, division and ex-
ponentiation are available for floats. For the first three, mixed mode operations are im-
plemented seamlessly, e.g., if addition of an int and a float is requested, then the int
3.3 Numbers 25

is automatically widened to be a float. The same applies for division if one operand is
an int and the other is a float. However, if both are ints, e.g., ±1/5, what is the result?
Earlier versions (< 3.0) of Python adopt integer division, 1/5=0 and -1/5=-1, while
versions  3.0 use real division, 1/5=0.2 and -1/5=-0.2. This is a potential pitfall
which is easily avoided. Either use integer division // or widen one of the operands to
ensure an unambiguous result.
Python has a useful feature inherited from its C roots. Suppose we wish to increment
the float referred to by a by two. Clearly the code

temp=a+2
a=temp

will work. However, it is faster and more efficient to use the single instruction

a+=2

The same applies of course to the other arithmetic operators.


Widening of an int to a float is available explicitly, e.g., float(4) will return either
4. or 4.0 . Narrowing of a float to an int is defined by the following algorithm. If x is
real and positive, then there exist an integer m and a float y such that

x = m + y, where 0  y < 1.0.

In Python, this narrowing is implemented via int(x), which returns m. If x is nega-


tive, then int(x)=-int(-x), succinctly described as “truncation towards zero”, e.g.,
int(1.4)=1 and int(-1.4)=-1.
In programming languages, we expect a wide range of familiar mathematical func-
tions to be available. Fortran builds in the most commonly used ones, but in the C-family
of languages we need to import them with a statement such as #include math.h at the
top of the program. Python also requires a module to be imported, and as an example we
consider the math module, which includes many standard mathematical functions for
real numbers. (Modules are defined in Section 3.4.) Suppose first that we do not know
what the math module contains. The following snippet first loads the module and then
lists the identifiers of its contents.

import math
dir(math) # or math.<TAB> in IPython

To find out more about the individual objects, we can either consult the written docu-
mentation or use the built-in help, e.g., in IPython

math.atan2? # or help(math.atan2)

If one is already familiar with the contents, then a quick-and-dirty-fix is to replace the
import command above by

from math import *


26 A Short Python Tutorial

anywhere in the code before invoking the functions. Then the function mentioned above
is available as atan2(y,x) rather than math.atan2(y,x), which at first sight looks
appealing. However, there is a another module, cmath, which includes many standard
mathematical functions for complex numbers. Now suppose we repeat the quick-and-
dirty fix.
from cmath import *

Then what does atan2(y,x) refer to? It is unambiguous to widen a real to a complex
number, but not in the other direction! Note that, unlike C, the import command can
occur anywhere in the program before its contents are needed, so chaos is waiting,
imperturbably, to wreck your calculation! Of course Python knows about this, and the
recommended workflow is described in Section 3.4.

3.3.3 Boolean numbers


For completeness, we include here Boolean numbers or bool, which are a subset of
the ints with two possible values, True and False, roughly equivalent to 1 (one) and 0
(zero).
Suppose that box and boy refer to bools. Then expressions such as “not box”,
“box and boy” and “box or boy” take on their usual meanings.
The standard equality operators are defined for ints and floats x, y, e.g., x==y (equal-
ity), x!=y (inequality). As a simple exercise, to remind you of the limitations of Python
floats, guess the result of the following line, next type it and then explain the result.
math.tan(math.pi/4.0)==1.0

However, for the comparison operators “x>y”, “x>=y”, “x<y” and “x<=y”, widening
takes place if necessary. Unusually, but conveniently, chaining of comparison operators
is allowed, e.g., “0<=x<1<y>z” is equivalent to
(0<=x) and (x<1) and (1<y) and (y>z)

Note that there is no comparison between x and y or z in this example.

3.3.4 Complex numbers


We have introduced three classes of numbers which form the simplest types of Python
object. These are the basis for classes of numbers that are more complicated. For exam-
ple rational numbers can be implemented in terms of pairs of integers. For our purposes,
a probably more useful class is that of complex numbers, which is implemented
√ in terms
of a pair of real numbers. Whereas mathematicians usually denote −1 by i, many en-
gineers prefer j, and Python has adopted the latter approach. Thus a Python complex
number can be defined explicitly by, e.g., c=1.5-0.4j. Note carefully the syntax: the
j (or equivalently J) follows the float with no intervening “∗”. Alternatively, a pair of
floats a and b can be widened to a complex number via c=complex(a,b). We can nar-
row a complex; e.g., with c as in the last sentence, c.real returns a and c.imag returns
3.4 Namespaces and Modules 27

b. Another useful object is c.conjugate(), which returns the complex conjugate of


c. The syntax of complex attributes will be explained in Section 3.10.
The five basic arithmetic operations work for Python complex numbers, and in mixed
mode widening is done automatically. The library of mathematical functions for com-
plex arguments is available. We need to import from cmath rather than math. However,
for obvious reasons, the comparison operations involving ordering, described above,
are not defined for complex numbers, although the equality and inequality operators are
available.
You have now seen enough of Python to use the interpreter as a sophisticated five-
function calculator, and you are urged to try out a few examples of your own.

3.4 Namespaces and Modules

While Python is running, it needs to keep a list of those identifiers which have been
assigned to objects. This list is called a namespace, and as a Python object it too has
an identifier. For example, while working in the interpreter, the namespace has the un-
memorable name __main__.
One of the strengths of Python is its ability to include files of objects, functions etc.,
written either by you or by someone else. To enable this inclusion, suppose you have
created a file containing objects, e.g., obj1, obj2 that you want to reuse. The file should
be saved as, e.g., foo.py, where the .py ending is mandatory. (Note that with most text
editors you need this ending for the editor to realize that it is dealing with Python code.)
This file is then called a module. The module’s identifier is foo, i.e., the filename minus
the ending.
This module can be imported into subsequent sessions via

import foo

(When the module is first imported, it is compiled into bytecode and written back to
storage as a file foo.pyc. On subsequent imports, the interpreter loads this precompiled
bytecode unless the modification date of foo.py is more recent, in which case a new
version of the file foo.pyc is generated automatically.)
One effect of this import is to make the namespace of the module available as foo.
Then the objects from foo are available with, e.g., identifiers foo.obj1 and foo.obj2.
If you are absolutely sure that obj1 and obj2 will not clash with identifiers in the
current namespace, you can import them via

from foo import obj1, obj2

and then refer to them as obj1 etc.


The “quick-and-dirty-fix” of Section 3.3.2 is equivalent to the line

from foo import *


28 A Short Python Tutorial

which imports everything from the module foo’s namespace. If an identifier obj1 al-
ready existed, its identifier will be overwritten by this import process, which usually
means that the object becomes inaccessible. For example, suppose we had an identifier
gamma referring to a float. Then

from math import *

overwrites this and gamma now refers to the (real) gamma-function. A subsequent

from cmath import *

overwrites gamma with the (complex) gamma-function! Note too that import statements
can appear anywhere in Python code, and so chaos is lurking if we use this option.
Except for quick, exploratory work in the interpreter, it is far better to modify the
import statements as, e.g.,

import math as re
import cmath as co

so that in the example above gamma, re.gamma and co.gamma are all available.
We now have sufficient background to explain the mysterious code line

if __name__ == "__main__"

which occurred in both of the snippets in Section 2.5. The first instance occurred in a
file fib.py. Now if we import this module into the interpreter, its name is fib and not
__main__ and so the lines after this code line will be ignored. However, when devel-
oping the functions in the module, it is normal to make the module available directly,
usually via the %run command. Then, as explained at the start of this section, the con-
tents are read into the __main__ namespace. Then the if condition of the code line is
satisfied and the subsequent lines will be executed. In practice, this is incredibly con-
venient. While developing a suite of objects, e.g., functions, we can keep the ancillary
test functions nearby. In production mode via import, these ancillary functions are ef-
fectively “commented out”.

3.5 Container Objects

The usefulness of computers is based in large part on their ability to carry out repeti-
tive tasks very quickly. Most programming languages therefore provide container ob-
jects, often called arrays, which can store large numbers of objects of the same type,
and retrieve them via an indexing mechanism. Mathematical vectors would correspond
to one-dimensional arrays, matrices to two-dimensional arrays etc. It may come as a
surprise to find that the Python core language has no array concept. Instead, it has con-
tainer objects which are much more general, lists, tuples, strings and dictionaries. It
will soon become clear that we can simulate an array object via a list, and this is how
3.5 Container Objects 29

numerical work in Python used to be done. Because of the generality of lists, such sim-
ulations took a great deal longer than equivalent constructions in Fortran or C, and this
gave Python a deservedly poor reputation for its slowness in numerical work. Devel-
opers produced various schemes to alleviate this, and they have now standardized on
the NumPy add-on module to be described in Chapter 4. Arrays in NumPy have much
of the versatility of Python lists, but are implemented behind the scenes as arrays in
C, significantly reducing, but not quite eliminating, the speed penalty. However, in this
section we describe the core container objects in sufficient detail for much scientific
work. They excel in the “administrative, bookkeeping chores” where Fortran and C are
at their weakest. Number-crunching numerical arrays are deferred to the next chapter,
but the reader particularly interested in numerics will need to understand the content of
this section, because the ideas developed here carry forward into the next chapter.

3.5.1 Lists
Consider typing the code snippet into the IPython terminal.

1 [1,4.0,’a’]
2 u=[1,4.0,’a’]
3 v=[3.14,2.78,u,42]
4 v
5 len(v)
6 len? # or help(len)
7 v*2
8 v+u
9 v.append(’foo’)
10 v

Line 1 is our first instance of a Python list, an ordered sequence of Python objects sepa-
rated by commas and surrounded by square brackets. It is itself a Python object, and can
be assigned to a Python identifier, as in line 2. Unlike arrays, there is no requirement that
the elements of a list be all of the same type. In lines 3 and 4, we see that in creating the
list an identifier is replaced by the object it refers to, e.g., one list can be an element in
another. The beginner should consult Figure 3.1 again. It is the object, not the identifier,
which matters. In line 5, we invoke an extremely useful Python function len() which
returns the length of the list, here 4. (Python functions will be discussed in Section 3.8.
In the meantime, we can find what len does by typing the line len? in IPython.) We
can replicate lists by constructions like line 7, and concatenate lists as in line 8. We can
append items to the ends of lists as in line 9. Here v.append() is another useful func-
tion, available only for lists. You should try v.append? or help(v.append) to see a
description of it. Incidentally, list. followed by tab completion or help(list) will
give a catalogue of functions intrinsic to lists. They are the analogue of c.conjugate()
in Section 3.3.4.
30 A Short Python Tutorial

3.5.2 List indexing


We can access elements of u by indexing, u[i] where i ∈ [0, len(u)) is an integer.
Note that indexing starts with u[0] and ends with u[len(u)-1]. So far, this is very
similar to what is available for arrays in, e.g., C or Fortran. However, a Python list such
as u “knows” its length, hence we could also index the elements, in reverse order, by
u[len(u)-k], where k ∈ (0, len(u)], which Python abbreviates to u[-k]. This turns out
to be very convenient. For example, not only is the first element of any list w referred to
by w[0], but the last element is w[-1]. The middle line of Figure 3.2 shows both sets
of indices for a list of length 8. Using the code snippet above, you might like to guess
the objects corresponding to v[1] and v[-3], and perhaps use the interpreter to check
your answers.
At first sight, this may appear to be a trivial enhancement, but it becomes very pow-
erful when coupled to the concepts of slicing and mutability, which we address next.
Therefore, it is important to make sure you understand clearly what negative indices
represent.

3.5.3 List slicing


Given a list u, we can form more lists by the operation of slicing. The simplest form of a
slice is u[start:end], which is a list of length end-start, as shown in Figure 3.2. If
the slice occurs on the right-hand side of an assignation, then a new list is created. For
example, su=u[2:6] generates a new list with four elements, where su[0] is initialized
with u[2]. If the slice occurs on the left, no new list is generated. Instead, it allows us
to change a block of values in an existing list. There are important new constructs here
which may well be unfamiliar to C and Fortran users.
Consider the simple example below which illustrates the possibilities, and, once you
have understood it, carry out further experiments of your own. This is best worked
through in IPython terminal mode.
1 u=[0,1,2,3,4,5,6,7]
2 su=u[2:4]
3 su
4 su[0]=17
5 su
6 u
7 u[2:4]=[3.14,’a’]
8 u

If start is zero, it may be omitted, e.g., u[ :-1] is a copy of u with the last element
omitted. The same applies at the other end, u[1: ] is a copy with the first element
omitted and u[:] is a copy of u. Here, we assume that the slice occurs on the right-hand
side of an assignation. The more general form of slicing is su = u[start:end:step].
Then su contains the elements u[start], u[start+step], u[start+2*step], . . . ,
as long as the index is less than start+end. Thus with the list u chosen as in the
3.5 Container Objects 31

        

     

        
       

         

Figure 3.2 Indices and slicing for a list u of length 8. The middle line shows the contents of u
and the two sets of indices by which the elements can be addressed. The top line shows the
contents of a slice of length 4 with conventional ordering. The bottom line shows another slice
with reversed ordering.

example above we would have u[2:-1:2]=[2,4,6]. A particularly useful choice is


step=-1, which allows traversal of the list in the reverse direction. See Figure 3.2 for
an example.

3.5.4 List mutability


For any container object u, it may be possible to modify an element or a slice, without
any apparent change having been applied to the object’s identifier. Such objects are said
to be mutable. As an example, consider a politician’s promises. In particular, lists are
mutable. There is a trap here for the unwary. Consider the code

1 a=4
2 b=a
3 b=’foo’
4 a
5 b
6 u=[0,1,4,9,16]
7 v=u
8 v[2]=’foo’
9 v
10 u

The first five lines should be comprehensible: a is assigned to the object 4; so is b. Then
32 A Short Python Tutorial

b is assigned to the object ’foo’, and this does not change a. In line 6, u is assigned to
a list object and so is v in line 7. Because lists are mutable, we may change the second
element of the list object in line 8. Line 9 shows the effect. But u is pointing to the same
object (see Figure 3.1) and it too shows the change in line 10. While the logic is clear,
this may not be what was intended, for u was never changed explicitly.
It is important to remember the assertion made above: a slice of a list is always a
new object, even if the dimensions of the slice and the original list agree. Therefore,
compare lines 6–10 of the code snippet above with
1 u=[0,1,4,9,16]
2 v=u[ : ]
3 v[2]=’foo’
4 v
5 u

Now line 2 makes a slice object, which is a copy4 of the object defined in line 1.
Changes to the v-list do not alter the u-list and vice versa.
Lists are very versatile objects, and there exist many Python functions which can
generate them. We shall discuss list generation at many points in the rest of this book.

3.5.5 Tuples
The next container to be discussed is the tuple. Syntactically it differs from a list only by
using () instead of [] as delimiters, and indexing and slicing work as for lists. However,
there is a fundamental difference. We cannot change the values of its elements: a tuple is
immutable. At first sight, the tuple would appear to be entirely redundant. Why not use a
list instead? The rigidity of a tuple however has an advantage. We can use a tuple where
a scalar quantity is expected, and in many cases we can drop the brackets () when there
is no ambiguity, and indeed this is the commonest way of utilizing tuples. Consider the
snippet below, where we have written a tuple assignation in two different ways.
(a,b,c,d)=(4,5.0,1.5+2j,’a’)
a,b,c,d = 4,5.0,1.5+2j,’a’

The second line shows how we can make multiple scalar assignments with a single
assignation operator. This becomes extremely useful in the common case where we need
to swap two objects, or equivalently two identifiers, say a and L1. The conventional way
to do this is
temp=a
a=L1
L1=temp

4 For the sake of completeness, we should note that this is a shallow copy. If u contains an element which is
mutable, e.g., another list w, the corresponding element of v still accesses the original w. To guard against
this, we need a deep copy to obtain a distinct but exact copy of both u and its current contents. For further
details inspect the copy module. In other words, try import copy followed by the line copy?
3.5 Container Objects 33

This would work in any language, assuming temp, a and L1 all refer to the same type.
However,

a,L1 = L1,a

does the same job in Python, is clearer, more concise and works for arbitrary types.
Another use, perhaps the most important one for tuples, is the ability to pass a variable
number of arguments to a function, as discussed in Section 3.8.4. Finally, we note a
feature of the notation which often confuses the beginner. We sometimes need a tuple
with only one element, say foo. The construction (foo) strips the parentheses and
leaves just the element. The correct tuple construction is (foo,).

3.5.6 Strings
Although we have already seen strings in passing, we note that Python regards them as
immutable container objects for alphanumeric characters. There is no comma separator
between items. The delimiters can be either single quotes or double quotes, but not a
mixture. The unused delimiter can occur within the string, e.g.

s1="It’s time to go"


s2=’ "Bravo!" he shouted.’

Indexing and slicing work in the same way as for lists.


There are two very useful conversion functions which can be associated with strings.
The function str() when applied to a Python object will produce a string representation
of that object. Among its many uses, the function eval acts as the inverse of str().
Consider the snippet

L = [1,2,3,5,8,13]
ls = str(L)
ls
eval(ls) == L

Strings will turn out to be very useful for the input of data, and, most importantly,
producing formatted output from the print function (see Sections 3.8.6 and 3.8.7).

3.5.7 Dictionaries
As we have seen, a list object is an ordered collection of objects, A dictionary object
is an unordered collection. Instead of accessing the elements by virtue of their position,
we have to assign a keyword, an immutable object, usually a string, which identifies
the element. Thus a dictionary is a collection of pairs of objects, where the first item in
the pair is a key to the second. A key–object pair is written as key:object. We fetch
items via keys rather than position. The dictionary delimiters are the braces { }. Here is
a simple example that illustrates the basics.
Another Random Scribd Document
with Unrelated Content
XIII
ESPOIR ET DÉSESPOIR

Le même soldat, devenu mon filleul de guerre, m'écrit encore:

«J'éprouve une joie ineffable à rester l'homme moyen et à


professer le vide. J'ai senti la grande paix descendre en moi, le
jour où je me suis résigné au sort commun, c'est-à-dire à
l'ignorance et à la mort. J'ai trouvé la vie en y renonçant, et me
sens très riche depuis que je ne suis plus rien. Ne me tentez pas
vers cette subtile vanité spirituelle qui constitue l'un des plus
formidables obstacles à la dernière libération du moi.
Orgueilleux, certes, je le fus, et ne le suis que trop encore, mais
nous ne pouvons extraire des vertus que de nos vices. Avec plus
d'ardeur que je n'ai embrassé le fantôme d'une supériorité
individuelle, je tends les bras vers l'égalité dans l'homogène,
vers la plénitude du vide…»

Il a raison, mais il pense ici avec le lobe oriental de son cerveau,


le lobe asiatique, et la pensée de ce lobe ne conseille que l'inaction,
le renoncement, «l'enchantement du désenchanté», comme disait
Renan, ou plutôt la satisfaction du désespoir. Il est certain que tout
ce que nous voyons, tout ce que nous sentons, tout ce que nous
savons, nous engage dans ce désespoir, que nos méditations—
surtout celles de ce même lobe asiatique—peuvent du reste rendre
très vaste, aussi beau et presque aussi habitable que l'espoir. Mais
que savons-nous, au regard de ce que nous ne savons pas? Nous
ignorons tout ce qui nous précède et tout ce qui nous suit, et, en un
mot, le tout de l'univers. Notre désespoir, qui paraît d'abord le
dernier mot et le dernier effort de la sagesse est donc fondé sur ce
que nous savons, qui n'est rien, tandis que l'espoir de ceux que nous
croyons moins sages peut se fonder sur ce que nous ignorons, qui
est tout.
Encore qu'il s'y mêle, si nous voulons être tout à fait justes, plus
d'une raison d'espérer que nous ne rappellerons pas ici; admettons
donc qu'en ce rien que nous savons ne se trouve que le désespoir, et
que l'espoir ne soit qu'en ce tout que nous ignorons. Mais au lieu de
n'écouter que notre lobe oriental qui nous conseille d'accepter cette
ignorance inactive et d'y ensevelir notre existence, n'est-il pas plus
raisonnable de faire travailler en même temps notre lobe occidental
qui cherche à découvrir ce tout? Il est possible qu'il y trouve aussi,
en fin de compte, le désespoir, mais c'est peu probable, car on ne
saurait imaginer un univers qui ne serait qu'un acte de désespoir. Or,
si l'univers n'est pas un acte de désespoir, rien de ce qui s'y trouve
n'a de raisons de désespérer. En tout cas et en attendant, cette
recherche nous permettra sans doute d'espérer aussi longtemps
qu'existera cet univers.

II

Une des plus dangereuses tentations qui assaillent celui qui se


penche sur la nature et qui voit, à mesure qu'il avance, les mystères
se multiplier et s'étendre en tous sens, à l'infini, c'est le
découragement devant la tâche impossible et le renoncement. Il
laisse tomber les armes. Surtout au dernier versant de la vie, il est
trop enclin à se résigner, à ne pas aller plus avant, à ne plus faire
d'effort, à s'endormir dans l'«à quoi bon?», à ne plus rien apprendre,
puisqu'il a appris qu'il ne saura jamais rien.
Il éprouve déjà ce désir de se rendre à merci, quand il envisage
la plus humble, la plus petite des sciences. Que sera-ce quand il
tentera de les embrasser toutes? L'esprit se perd, a le vertige et
demande à fermer les yeux. Il ne faut pas les fermer. C'est la plus
basse trahison que puisse commettre l'homme. Nous n'avons pas
autre chose à faire en cette vie qu'à chercher à savoir où nous
sommes. Nous ne nous trouvons pas d'autre raison d'être, nous
n'avons pas d'autre devoir. Ne pas savoir n'est qu'un désagrément;
ne plus chercher à savoir est le malheur suprême et sans remède, la
désertion inexcusable.
Pourtant, sans renoncer, il est bon de ne pas se nourrir de trop
petites illusions. Ayons toujours devant les yeux certaines vérités qui
nous remettent à notre place. Il est certain que nous ne saurons
jamais tout, et tant que nous ne saurons pas tout, nous serons
comme si nous ne savions rien. Il est fort possible, comme l'insinue
le Rig-Véda, que Dieu lui-même, ou la cause première ne sache pas
tout. Il est également possible que l'univers n'ait encore, en aucune
de ses parties, pris conscience de soi, ignore d'où il vient et où il va,
ce qu'il fut et ce qu'il sera, ce qu'il a fait comme ce qu'il veut faire;
et, d'autre part, il est probable que s'il ne l'a pas appris, il ne
l'apprendra jamais, attendu, ainsi que je l'ai déjà dit, qu'il n'y a
aucune raison pour qu'il puisse faire dans l'infini des temps qui nous
suivra ce qu'il n'a pu faire dans l'infini des temps qui nous précéda.
S'il y a une conscience de l'univers ou un Dieu, il sait tout ce qu'il
doit savoir ou ne le saura jamais. Et s'il le sait, pourquoi a-t-il fait ce
qu'il a fait, qui ne peut mener à rien; attendu qu'il nous aurait déjà
menés où il faudrait aller? Pourquoi n'a-t-il pas préféré le néant ou
du moins ce que nous appelons le néant, seule forme du bonheur
stable, immuable, incontestable et compréhensible?
Nous comprendrions peut-être, et encore serait-ce bien difficile,
un univers immobile, immuable, éternel, un univers arrivé; nous ne
pouvons comprendre un univers en mouvement ou dont, tout au
moins, toutes les parties que nous voyons sont sans cesse en
mouvement et en évolution à travers l'espace et le temps, un univers
se précipitant à des vitesses vertigineuses vers un but qu'il
n'atteindra jamais puisqu'il ne l'a pas encore atteint.
On peut dire, pour se consoler, que tout désespoir ne vient que
de l'étroitesse de notre vue, mais il convient d'ajouter qu'il en est de
même de tout espoir.
XIV
MACROCOSME ET MICROCOSME

Les biologistes constatent que l'embryon humain récapitule—très


rapidement durant les premiers mois de son évolution, plus
lentement dans les derniers—toutes les formes de vie qui ont
précédé l'homme sur cette terre.
La tache arrondie qu'est le germe devient une sphère creuse,
une sorte de sac à paroi double, qu'on appelle Gastrula et dont
l'orifice d'invagination resserré prend le nom de Blastopore. C'est la
vie protozoaire, le début, encore gélatineux, de la vie animale, à
laquelle succède, à la suite de transformations qu'il serait trop long
d'énumérer, la vie polypéenne.
Puis, de chaque côté de la tête, apparaissent les «arcs
branchiaux», qui correspondent aux branchies des poissons. A la fin
du premier mois, les membres ne sont encore que de simples
bourgeons; par contre, l'embryon est pourvu d'une queue qui,
repliée, lui touche presque le front. Il a alors l'aspect d'un têtard et
vit d'une vie toute aquatique, baigné dans le liquide amniotique qui
représente pour lui l'eau dans laquelle évoluent librement les
embryons des poissons et des batraciens.
Il s'agit maintenant de prendre une résolution et de savoir ce
qu'on en fera. Il se trouve à peu près dans la situation où se trouvait
la vie à l'origine des espèces; et la nature, comme pour humilier
l'homme ou s'humilier elle-même en se remémorant ses erreurs et
ses hésitations, recommence ses tâtonnements, ses impairs, ses
repentirs et ses expériences ratées. Des formes ébauchées, comme
la corde dorsale, se résorbent, les reins primitifs disparaissent pour
faire place aux reins définitifs qui sont gigantesques et remplissent la
plus grande partie de la cavité péritonéale. Gigantesque est aussi le
foie qui envahit presque toute la cavité viscérale, gigantesque la tête
presque aussi grosse que le reste du corps; et dans cette
gigantesque tête se forment les vésicules oculaires primitives qui
sont également énormes, comme est énorme la vésicule ombilicale.
C'est la période incohérente et monstrueuse qui correspond à
l'époque de démence et de gigantisme où la nature, encore
inexpérimentée, ébauchait aveuglément des êtres incertains,
formidables, hétéroclites, déséquilibrés, à la fois oiseaux, crocodiles,
éléphants et poissons, comme si elle n'avait pas encore pris son
parti, opéré ses classifications, dégagé ses lois et acquis le sens des
proportions, de la mesure et des conditions essentielles au maintien
de la vie qu'elle créait.

Voilà, en gros, la récapitulation qui se passe sous nos yeux; mais


dont, sans doute, beaucoup d'incidents nous échappent ou ne fixent
pas assez notre attention, car il est possible qu'ils reproduisent des
formes que nous ne connaissons pas, qui n'ont même pas laissé de
traces géologiques, attendu que le nombre des espèces disparues
est infiniment plus grand que celui des espèces que nous
connaissons.
Le docteur Hélan Jaworski peut donc très justement affirmer que
la période embryonnaire correspond à la période géologique. Et de
même que dans la grande évolution terrestre, nous voyons
disparaître peu à peu les poissons cuirassés, les monstrueux reptiles,
les gigantesques mammifères, dans la petite évolution
embryonnaire, nous voyons se dissoudre le rein primitif, la corde
dorsale, la vésicule ombilicale, le foie diminuer, la disproportion de la
tête au reste du corps s'amoindrir, en un mot la nature s'assagir,
reconnaître ses torts, profiter de son expérience, réparer de son
mieux ses erreurs et, peu à peu, acquérir le sens de l'équilibre, de
l'économie et de la mesure.
Entre la période géologique qui correspond à l'apparition de
l'homme sur la terre et la naissance de l'enfant, le docteur Jaworski
trouve d'autres analogies ingénieuses mais un peu plus risquées.
L'accouchement est, en effet, précédé d'un déluge en miniature
causé par le déchirement des enveloppes fœtales qui laissent
échapper le liquide amniotique. Puis, l'enfant, au moment où il entre
dans la vie, connaît brusquement une sorte de période glaciaire. Il
passe, en effet, d'un milieu où règne une température de plus de
trente-sept degrés, à l'air extérieur qui en compte à peine seize ou
dix-huit. L'impression de froid est si terrible qu'elle arrache au
nouveau-né son premier cri de douleur.

Quelle est la signification de cette étrange récapitulation?


Le docteur Jaworski est d'avis que si la petite évolution
embryonnaire qui prépare la naissance de l'homme, répète la grande
évolution terrestre, cette dernière ne serait de son côté qu'une vaste
période embryonnaire qui préparerait une naissance qu'on ne peut
pas encore imaginer. Je ne sais s'il réussira à étayer suffisamment
cette gigantesque hypothèse. S'il y parvient, il nous aura réellement
fait faire, ainsi qu'il le promet, «un pas dans l'essence des choses».
En attendant, par ses travaux préparatoires, il nous aura toujours
fait faire un autre pas très utile, vers une vérité, incontestable, cette
fois, qui, pour être moins inattendue n'a jamais été mise en lumière
avec autant de patience et n'est pas moins grosse de conséquences.

Le docteur Jaworski entreprend donc de démontrer que le corps


de l'homme réunit en lui, nettement reconnaissables, tous les êtres
vivants qui existent actuellement sur cette terre et qui y ont existé
depuis l'origine de la vie. En d'autres termes, chaque être résume en
lui tous ceux qui l'ont précédé; et l'homme, le dernier venu,
renferme l'Arbre biologique tout entier, à tel point que si l'on
dissociait son corps, si l'on pouvait séparer chacun de ses organes et
les maintenir isolément en vie, on parviendrait à reconstituer toutes
les formes existantes, à repeupler la terre de toutes les espèces
qu'elle a portées, depuis le protoplasme primitif jusqu'à cette
synthèse, cet aboutissement que nous sommes.
On pourrait aller plus loin et affirmer, comme le font les
occultistes orientaux, que nous renfermons également en nous, en
germe ou à l'état d'ébauche, tous les êtres, toutes les formes qui
viendront après nous. Mais ici nous quitterions la science
proprement dite pour nous égarer dans une hypothèse
naturellement invérifiable.

Ainsi donc, ce n'est pas seulement au figuré, comme le


pressentait le langage courant quand il parle de l'arbre vasculaire,
des rameaux nerveux, de la grappe ovarienne, ce n'est pas
seulement par analogie mais au pied de la lettre et dans toute la
rigueur scientifique que notre cœur n'est au fond qu'une méduse,
que nos reins sont des éponges, que nos intestins représentent les
polypes et notre squelette les polypiers, que nos organes
reproducteurs sont des vers ou des mollusques, que la colonne
vertébrale et la moelle épinière remplacent les échinodermes, tandis
que les brachiopodes et les cténophores renaîtraient de notre œil,
que les reptiles se retrouveraient dans notre appareil digestif et les
oiseaux dans notre appareil respiratoire; et ainsi de suite.
Je le répète, il ne s'agit pas ici de métaphores et de
correspondances plus ou moins approximatives, élastiques et
plausibles, mais de constatations rigoureusement et
méticuleusement établies.
Je ne puis naturellement vous mettre sous les yeux les détails de
la démonstration du docteur Jaworski. Elle ne saurait admettre la
moindre solution de continuité, et, à travers les trois volumes publiés
jusqu'ici, nous mène à des conclusions qu'il est bien difficile de
contester. On affirmait sans trop y croire et sans y regarder de trop
près que l'homme est un microcosme. Il semble bien prouvé
aujourd'hui que ce n'est pas seulement littérairement défendable,
mais scientifiquement exact. Nous sommes une colonie
préhistorique, immense et innombrable, une agglomération vivante
de tout ce qui vit, a vécu et probablement vivra sur la terre. Nous ne
sommes pas seulement les fils ou les frères des vers, des reptiles,
des poissons, des batraciens, des oiseaux, des mammifères ou de
n'importe quel monstre qui a souillé ou épouvanté la surface du
globe; nous les portons en nous, nos organes ne sont qu'eux, nous
en nourrissons tous les types, ils n'attendent qu'une occasion pour
s'évader de nous, reparaître, se reconstituer, se développer et nous
replonger dans la terreur. A leur propos, aussi justement qu'à propos
des pensées secrètes, des vices et des fantômes qui nous peuplent,
on pourrait répéter le mot que le vieillard d'Emerson disait à ses
enfants affolés par une étrange figure dans la sombre entrée: «Mes
enfants, vous ne verrez jamais rien de pire que vous-mêmes!» Si
toutes les espèces disparaissaient et que seul l'homme subsistât,
aucune ne serait perdue et toutes pourraient renaître de son corps,
comme si elles sortaient de l'Arche de Noé, depuis le protozoaire
presque invisible, jusqu'aux formidables colosses d'avant le déluge
qui lècheraient les toits de nos maisons.
Il est donc assez probable que toutes ces espèces prennent part
à notre existence, à nos instincts, à tous nos sentiments, à toutes
nos pensées; et nous voici une fois de plus ramenés aux grandes
religions de l'Inde qui avaient pressenti toutes les vérités que nous
découvrons peu à peu et, il y a des milliers d'années, nous
affirmaient déjà que l'homme est tout et doit reconnaître son
essence en tout être vivant.
XV
L'HÉRÉDITÉ ET LA PRÉEXISTENCE

Il y a dans la loi de l'hérédité qui veut que les descendants


souffrent des fautes et profitent des vertus de leurs ancêtres des
vérités qui ne sont plus contestées. Elles éclatent à tous les yeux. Le
fils d'un alcoolique portera toute sa vie, de sa naissance à sa mort,
dans sa chair et dans son esprit, le poids du vice paternel. On dirait
que par cet exemple irrécusable, la nature a voulu affirmer et
manifester avec ostentation le caractère implacable de sa loi; comme
pour nous faire entendre qu'elle ne tient aucun compte de nos
notions du juste et de l'injuste et agit selon le même principe dans
toutes les ténébreuses circonstances où nous ne pouvons suivre les
inextricables détours de sa volonté.
Il n'y aurait que cet exemple, qu'il suffirait à marquer d'infamie
cette volonté inhumaine. Il n'y a pas de loi qui répugne davantage à
notre raison, à notre sens des responsabilités, qui altère plus
profondément notre confiance à l'univers et à l'esprit inconnu qui le
dirige. De toutes les injustices de la vie, voici la plus criante, la
moins compréhensible. Nous trouvons des excuses ou des
explications à la plupart des autres; mais qu'un enfant qui vient de
naître, qui n'a pas demandé à naître, soit, dès la première gorgée
d'air qu'il aspire, frappé d'une déchéance irrémédiable, d'une
condamnation féroce, irrévocable et de maux qu'il traînera jusqu'au
tombeau, il nous semble qu'aucun des tyrans les plus odieux que
l'histoire ait maudits n'aurait osé faire ce que la nature fait
paisiblement chaque jour.
Mais portons-nous vraiment le poids de la faute des morts?
D'abord, est-il bien sûr que les morts soient réellement morts et ne
demeurent plus en nous? Il est certain que nous les prolongeons,
que nous sommes la partie durable de ce qu'ils furent. Nous ne
saurions nier que nous subissons encore leur influence, que nous
reproduisons leurs traits et leur caractère, que nous les représentons
presque tout entiers, qu'ils continuent de vivre et d'agir en nous; il
est donc assez naturel qu'ils continuent également de supporter les
conséquences d'une action ou d'une façon de vivre que leur départ
n'a pas interrompue.
Mais, dira-t-on, je n'ai pas participé à cette action, à cette
habitude, à ce vice que je paie aujourd'hui. Je n'ai pas été consulté,
je n'ai pas eu l'occasion d'élever la voix, de retenir sur la pente fatale
mon père ou mon aïeul qui se perdait. Je n'étais pas né, je n'existais
pas encore.—Qu'en savons-nous?—N'y aurait-il pas, dans l'idée que
nous nous faisons de l'hérédité, une erreur fondamentale? A l'un des
bouts du fléau de la balance que nous accusons d'injustice, pend
l'hérédité; mais à l'autre bout pèse autre chose dont on n'a jamais
tenu compte, car elle n'a pas encore de nom, qui est le contraire de
l'hérédité, qui plonge dans l'avenir au lieu de sortir du passé et qu'on
pourrait appeler la préexistence ou la prénatalité.
De même que nos morts vivent toujours en nous, nous vivons
déjà dans nos morts. Il n'y a aucune raison de croire que l'avenir, qui
est plein de vie, soit moins actif et moins puissant que le passé qui
est plein de morts. Au lieu de le descendre, ne faudrait-il pas
remonter le cours des ans pour retrouver la source de nos actes?
Nous ignorons de quelle façon ceux qui, jusqu'aux dernières
générations, naîtront de nous, vivent déjà en nous; mais il est
certain qu'ils y vivent. Quel que soit, dans la suite des âges, le
nombre de nos descendants, quelles que soient les transformations
que leur fassent subir les éléments, les climats, les terroirs et les
siècles, ils garderont intacts, à travers toutes les vicissitudes, le
principe de vie qu'ils ont tiré de nous. Ils ne l'ont pas pris ailleurs ou
ne seraient pas ce qu'ils sont. Ils sont réellement sortis de nous; et
s'ils en sont sortis, c'est que d'abord ils s'y trouvaient. Que faisaient
donc en nous ces innombrables vies accumulées? Est-il permis de
prétendre qu'elles y demeuraient absolument inactives? Quelles
étaient leurs fonctions, leur puissance? Qu'est-ce qui les séparait de
nous? Où commencions-nous, où finissaient-elles? A quel point se
mêlaient aux nôtres leurs pensées et leur volonté?
Elles n'avaient pas encore de cerveau, direz-vous, comment
pouvaient-elles penser et agir en nous? Il est vrai, mais elles avaient
le nôtre. Les morts sont également privés de cerveau; néanmoins
personne ne conteste qu'ils continuent de penser et d'agir en nous.
Ce cerveau dont nous sommes si fiers, n'est pas la source, mais le
condensateur de la pensée et de la volonté. Comme la bouteille de
Leyde ou la bobine de Rhumkorff, il n'existe et ne s'anime que
durant le temps qu'y passe ou qu'y réside le fluide électrique de la
vie. Il ne produit pas ce fluide, il le recueille; ce qui importe, ce n'est
point ses circonvolutions, comparables aux fils d'une bobine
d'induction, mais la vie qui le parcourt; et que peut être cette vie,
sinon le total de toutes les existences que nous accumulons en nous,
qui ne s'éteignent pas à notre mort, commencent avant notre
naissance et nous prolongent, en avant et en arrière, dans l'infini du
temps?
On a parfois, dans des études ou des romans, essayé de mettre
en scène ces vies diverses que nous hébergeons; et chacun de nous,
s'il s'interroge sincèrement et profondément, découvrira en soi deux
ou trois types très nets, qui n'ont de commun que le corps où ils
séjournent, ne s'entendent guère entre eux, luttent sans cesse pour
avoir le dessus et s'arrangent comme ils peuvent afin d'aller jusqu'au
bout d'une existence dont l'ensemble forme notre moi. Ce moi sera
bon ou mauvais, remarquable ou insignifiant, plus ou moins égoïste
ou généreux, inquiet ou tranquille, pacifique ou belliqueux, héroïque
ou pusillanime, hésitant ou décidé et entreprenant, sauvage ou
raffiné, fourbe ou loyal, actif ou paresseux, chaste ou lubrique,
modeste ou vaniteux, fier ou obséquieux, inégal ou constant, selon
l'autorité que saura prendre sur les autres le type qui s'emparera des
meilleures positions du cœur ou du cerveau. Mais même dans
l'existence en apparence la plus stable, la plus une, la mieux
équilibrée, cette autorité ne sera jamais incontestée ni définitive. Le
type dominant se verra toujours discuté, attaqué, inquiété,
circonvenu, harcelé, contrarié, sollicité, trompé, trahi et parfois
sournoisement détrôné par un des types rivaux ou subalternes, dont
il ne se méfiait pas ou qu'il ne surveillait plus assez étroitement. Il y
a des coalitions inattendues, des compromis bizarres, des défections
regrettables, des compétitions, des intrigues incessantes, de
véritables coups d'état, notamment aux âges critiques et à chaque
événement important; et toute cette tragédie intime et prodigieuse
ne s'arrête un moment qu'à l'instant de la mort.
Mais encore une fois, pourquoi chercher uniquement dans le
passé et parmi les ancêtres, les acteurs de ce drame qui est le
drame humain par excellence? Qu'est-ce qui nous permet de
supposer que les morts seuls y tiennent tous les rôles? Pourquoi
ceux dont nous sommes sortis auraient-ils plus d'influence que ceux
qui sortiront de nous? Les premiers sont loin de notre corps,
d'insondables mystères les en séparent, et leur survivance peut être
mise en doute; les autres habitent notre chair et leur existence ne
saurait être contestée. Nous venons de voir que l'argument que l'on
tire de l'absence de tout cerveau n'est pas invincible. Mais, ajoutera-
t-on peut-être, comment voulez-vous que, n'ayant pas encore vécu,
ils puissent avoir des habitudes, des vertus et des vices, des
préférences et une expérience, en un mot, tout ce qui constitue un
caractère et ne s'acquiert qu'au contact de la vie? Mais la même
objection, dans la plupart des cas, pourrait être faite au sujet des
ancêtres. En général, quand nous sommes sortis d'eux, ils étaient
encore jeunes, ils n'étaient pas encore ce qu'ils sont devenus et ce
que nous devenons d'après eux. Ils n'avaient pas encore pris les
habitudes, la manière de penser ou de sentir, cultivé les vertus ou
les vices que nous reproduisons. Le petit bourgeois maniaque,
économe, circonspect et mesquin que nous sentons en nous, était
peut-être encore un jeune homme prodigue, ardent et inconsidéré;
le débauché était peut-être chaste, le voleur n'avait jamais volé et
l'assassin pouvait avoir horreur du sang. Tout est à peu près
également immatériel, et virtuel dans les deux cas; il ne s'agit ici que
de tendances et de forces amorphes auxquelles le cerveau que nous
tenons des uns, que nous passons aux autres, donne une forme.
Il est donc fort possible que le petit bourgeois, le débauché, le
voleur ou l'assassin, loin d'être morts, ne soient pas encore nés et
prennent une part aussi active que nos ancêtres aux agitations et
parfois à la direction de notre vie. C'est ce qu'ont toujours pressenti
ou révélé, le tenant peut-être d'une source inconnue et plus haute,
les religions les plus anciennes et les plus vénérables de l'humanité,
dont le christianisme et son dogme du péché originel ne sont qu'une
réplique incomplète. Aujourd'hui encore, plus de six cents millions
d'hommes croient à la préexistence des âmes, aux vies successives
et à la réincarnation. Aux yeux de ces religions, le petit bourgeois qui
nous procréa, il y a plusieurs siècles, est le même qui, un peu moins
mesquin, un peu moins borné, amélioré par sa vie antérieure et le
passage à travers les mystères de la mort, attend en nous le
moment de renaître et, en l'attendant, se mêle à nos instincts, à nos
sentiments, à nos pensées. Il n'y attend pas seul; il n'est qu'une vie
dans la foule des vies qui nous ont précédés et viennent revivre en
nous; et toutes ces vies passées et futures forment l'ensemble de la
nôtre.
Nous ne discuterons pas ici cette doctrine des existences
successives et de la réincarnation expiatrice et purificatrice, qui est
l'explication la plus haute et, jusqu'à ce jour, la seule acceptable
qu'on ait trouvée aux injustices de la nature. En l'état présent de nos
connaissances, elle ne peut être qu'une hypothèse magnifique ou
une affirmation qu'il est impossible de prouver. Ne quittons pas le
terrain incontestable où se trouvent l'hérédité et la préexistence.
L'hérédité est un fait acquis, une vérité expérimentale, la
préexistence est une nécessité logique. On ne saurait, en effet,
concevoir que ce qui naîtra de nous, déjà n'existe pas en nous, en
fait, en principe, en germe, en essence ou en puissance; et, dès lors
qu'il existe d'une façon probablement plus spirituelle que matérielle,
il est bien moins surprenant qu'il porte plus ou moins la
responsabilité de pensées et d'actes auxquels il ne saurait être
entièrement étranger.
En tout cas, l'hérédité incontestable et la préexistence nécessaire
nous rappellent une fois de plus que chacun de nous n'est pas un
être unique, isolé, permanent, hermétiquement clos, indépendant
des autres et séparé de tout dans l'espace et le temps, mais un vase
poreux plongé dans l'infini, une sorte de carrefour où se croisent
toutes les routes du passé, du présent et de l'avenir, une auberge au
bord des chemins éternels, où se réunissent, pour y passer quelques
jours, toutes les vies qui forment notre vie. Nous nous croyons morts
quand elles quittent l'auberge, et nous nous imaginons qu'elles
périssent aussi. Il est plus vraisemblable qu'il n'en est rien. Elles
abandonnent simplement l'hôtellerie délabrée pour s'installer dans
une maison nouvelle et plus habitable. Elles y emportent leurs
créances et leurs dettes, y emménagent leurs habitudes, leurs
instincts, leurs idées, leurs passions, leurs mérites, leurs fautes, leurs
acquisitions et leurs souvenirs. La maison est changée, mais les
hôtes sont les mêmes et l'existence d'autrefois reprendra son cours
dans la demeure nouvelle, peut-être un peu plus haute, peut-être un
peu plus belle, peut-être un peu plus claire…
XVI
LA GRANDE RÉVÉLATION

Nous désespérons de connaître jamais l'origine de l'univers, son


but, ses lois, ses intentions, et nous finissons par douter qu'il en ait.
Il serait plus sage de très humblement nous dire que nous ne
sommes pas à même de les concevoir. Il est probable que s'il nous
livrait demain la clef de son énigme, nous serions, autant qu'un
chien à qui l'on montre la clef d'une horloge, incapable d'en
comprendre l'usage. En nous révélant son grand secret, il ne nous
apprendrait presque rien, ou du moins cette révélation n'aurait
qu'une influence insignifiante sur notre vie, notre bonheur, notre
morale, nos efforts et nos espérances. Elle planerait à de telles
hauteurs que personne ne l'apercevrait; tout au plus débarrasserait-
elle le ciel de nos illusions religieuses, ne laissant, à la place qu'elles
y occupaient, que le vide infini de l'éther.

Il n'est pas dit, du reste, que nous ne possédions pas cette


révélation. Il est fort possible que les religions de peuples disparus,
Lémures, Atlantes et beaucoup d'autres, l'aient connue; et que nous
en retrouvions les débris dans les traditions ésotériques parvenues
jusqu'à nous. Il ne faut pas oublier, en effet, qu'à côté de l'histoire
extérieure et scientifique, existe une histoire secrète de l'humanité
qui tire sa substance de légendes, de mythes, d'hiéroglyphes, de
monuments étranges, d'écrits mystérieux, du sens caché des livres
primitifs. Il est certain que si l'imagination des interprètes de cette
histoire occulte est souvent hasardeuse, tout ce qu'ils affirment n'est
pas à dédaigner et mériterait d'être un jour examiné plus
sérieusement qu'on ne l'a fait jusqu'ici.
L'essentiel de cette révélation ésotérique est fort bien résumé par
M. Marc Saunier, disciple de Fabre d'Olivet et de Saint-Yves
d'Alveydre, dans son livre: la Légende des Symboles. «Les Initiés,
dit-il, ont toujours considéré chaque continent comme un être
soumis aux mêmes lois que l'homme. Pour eux, les minéraux en
constituent l'ossature, la flore, la chair, la faune, les cellules
nerveuses, et les races humaines, la substance grise du cerveau. Ce
continent ne serait lui-même qu'un organe de la terre dont chaque
homme serait une cellule pensante, et dont la totalisation des
pensées humaines exprimerait la pensée. La terre elle-même ne
serait qu'un organe du système solaire considéré à son tour comme
individu, et notre système solaire ne serait lui aussi qu'un organe
d'un autre être de l'infini, dont l'étoile Alpha du Bélier manifesterait
le cœur. Et enfin, par une dernière synthèse, on arrive au Cosmos
qui exprime la totalisation générale de tout, en un être dont le corps
est le monde, et la pensée, l'intelligence universelle, divinisée par les
religions.»

Le fond de leur doctrine est nettement évolutionniste. Chaque


continent n'a fait que transformer à son heure, et selon son idéal, les
germes issus des terres hyperboréennes, et l'homme n'est que le
résultat d'une évolution animale. Ils l'empruntent d'ailleurs presque
totalement aux Hindous et précèdent ainsi de plusieurs milliers
d'années les dernières hypothèses de notre science actuelle.
Mais, sans nous attarder dans ces sables mouvants, allons
directement aux sources claires et sûres. Nous possédons, en effet,
dans les livres sacrés et secrets de l'Inde, dont nous ne connaissons
d'ailleurs qu'une infime partie, une cosmogonie qu'aucune pensée
européenne n'a jamais dépassée. Il ne serait pas juste de dire que
du premier coup elle atteignit les dernières limites où l'intelligence
de l'homme puisse se hasarder sans se dissoudre dans l'infini, car
elle est l'œuvre de siècles dont nous ne savons pas le nombre; mais
il est incontestable qu'elle précède toutes les autres, que sa
naissance est antérieure à tout ce que nous connaissons, et qu'à
l'origine de tout, elle est allée au delà de tout ce que nous avons
appris et de tout ce que nous pouvons imaginer de plus grand.

La première, par exemple, bien avant nos temps historiques, elle


a su nous donner une idée concrète et vertigineuse de l'infini du
temps. Le livre de Manou nous apprend que douze mille années des
mortels ne représentent pour les dieux qu'un jour et une nuit; leur
année composée de trois cent soixante jours compte donc quatre
millions trois cent mille ans. Mille années des dieux ne forment à leur
tour qu'un seul jour de Brahma, c'est-à-dire quatre milliards trois
cent vingt millions d'années humaines, représentant la vie totale de
notre globe; et la nuit de Brahma est d'égale durée. Trois cent
soixante de ces jours et nuits font une année de ce dieu, et cent de
ces années constituent une de ses vies, c'est-à-dire la durée de
l'univers représentée par le chiffre formidable de trois cent onze
mille et quarante milliards d'années. Après quoi, il recommence une
autre vie. En ce moment, nous n'avons pas encore atteint le midi du
jour actuel de Brahma, ni la moitié de la vie de notre globe terrestre.
Pour compléter cette esquisse de l'immense chronologie védique,
je continue de me servir des notes que veut bien me confier mon
filleul de guerre qui possède à fond cette science trop négligée. On
verra du reste que chronologie et cosmogonie sont ici intimement
liées.
«La journée de Brahma (quatre milliards trois cent vingt millions
d'années) se décompose en quatorze vies de Manou, dont sept
Manvantaras et sept Pralayas alternatifs. Le mot Manvantara veut
dire intervalle entre deux Manous: l'un de ceux-ci apparaît à l'aurore
et l'autre au crépuscule de cette période d'activité terrestre. Le
Manou matinal donne son nom au Manvantara, et le Manou vespéral
préside au Pralaya, c'est-à-dire à la période de dissolution, ou de
statu quo négatif, mort, sommeil ou inertie selon le cas, qui sépare
deux vagues de vie.
«L'évolution universelle est une chaîne sans commencement ni
fin dont chaque anneau apparaît et disparaît tour à tour dans notre
champ de conscience. Brahma lui-même ne meurt que pour renaître.
Mais pour le souverain des mondes comme pour un astre
quelconque ou pour le dernier des êtres organiques, il n'y a de mort
et de dissolution qu'au point de vue individuel. L'obscurité est la
rançon de la lumière, le soir compense le matin, la vieillesse est le
prix de la jeunesse et la mort le revers de la vie. En réalité
cependant, toute évolution est continuelle en même temps que
discontinue; les Manvantaras et Pralayas sont à la fois simultanés et
successifs; chaque vie individuelle est engendrée par son double
élémental et engendre son double résidual. Tout déclin de vie dans
un lieu donné coïncide avec une croissance d'être dans un lieu
correspondant et se poursuit par une renaissance en un lieu
nouveau. Au fond, il n'y a pas de vie individuelle. Nous sommes à la
fois nous-même et un autre, nous-même et plusieurs autres, nous-
même et tous les autres, nous-même et l'univers, nous-même et
l'infini.
«L'évolution de notre globe terrestre est un cycle infinitésimal de
cette évolution universelle, correspondant seulement à un jour et
une nuit de Brahma et se divise en quatorze cycles composés
chacun d'un Manvantara et d'un Pralaya. Le cycle de l'évolution
organique sur notre globe solidifié représente une seule de ces
subdivisions, c'est-à-dire que le rayon de la sphère organique n'est
qu'un quatorzième du rayon de la sphère minérale. L'évolution
minérale est évidemment continue, de la formation à la dissolution
du globe. Si, entre les périodes d'activité géologiques, il existe un
Pralaya quelconque, celui-ci, en dépit de l'étymologie du mot, doit
être, non pas une dissolution parfaitement inconcevable au point de
vue logique et scientifique, mais une période d'inertie ou de
ralentissement, dont l'hypothèse est très admissible, et dont les
périodes glaciaires survenues au cours même du Manvantara actuel
nous offrent un exemple. Dans les cycles antérieurs de Manou, la
terre a passé successivement par les divers états de condensation
que la science considère comme ignés et qui correspondent à
l'évolution élémentaire, éthérée, gazeuse et liquide. Pendant ces
longues périodes, la vie actuelle existait en potentialité dans l'âme
de la terre et en réalité sur d'autres globes que le nôtre.»
Mais ne poussons pas plus loin cette esquisse dont la
complication deviendrait inextricable. Rappelons simplement cette
magnifique doctrine de la réincarnation qui, à toutes les questions
du juste et de l'injuste, immortelle torture des mortels, est la
réponse la plus ancienne, la seule décisive et sans doute la plus
plausible; et son corollaire, cette loi du Karma comme le dit si bien
mon filleul, «la plus admirable des découvertes morales: elle
représente la liberté abstraite, et suffit à affranchir la volonté
humaine de tout être supérieur ou même infini. Nous sommes nos
propres créateurs et les seuls maîtres de notre destin; nul autre que
nous-même ne nous récompense ou ne nous punit; il n'y a pas de
péché, mais seulement des conséquences; il n'y a pas de morale,
mais seulement des responsabilités. Or, le Bouddha enseignait qu'en
vertu même de cette loi souveraine, l'individu doit renaître pour
moissonner ce qu'il a semé: cette certitude de renaissance suffisait à
neutraliser l'horreur de la mort.»

Tout cela n'est-il qu'imaginaire, rêves de cerveaux plus ardents


que les nôtres, hallucinations d'ascètes qu'étourdissent le jeûne et
l'immobilité ou échos de traditions immémoriales laissées par
d'autres races ou des êtres antérieurs à l'homme et plus spirituels? Il
est impossible de s'en rendre compte, mais quelle qu'en soit
l'origine, il est certain que le monument, dont nous n'avons entrevu
qu'un angle de la base, est prodigieux et n'a pas l'air humain. Tout
ce qu'on peut dire, c'est que nos sciences modernes, notamment
l'archéologie, la géologie et la biologie, confirment plus qu'elles
n'infirment l'une ou l'autre de ces révélations.

Mais là n'est pas, pour l'instant, la question. Admettons que l'une


d'elles, celle des livres sacrés de l'Inde, par exemple, soit vraie,
incontestable et scientifiquement établie par nos recherches, ou
qu'une communication interplanétaire ou une déclaration d'un être
surhumain ne permette plus de douter de son authenticité: quelle
influence une telle révélation aura-t-elle sur notre vie? Qu'y
transformera-t-elle, quel élément nouveau apportera-t-elle à notre
morale, à notre bonheur? Sans doute fort peu de chose. Elle passera
trop haut, elle ne descendra pas jusqu'à nous, elle ne nous touchera
point, nous nous perdrons en son immensité, et, au fond, sachant
tout, nous ne serons ni plus heureux ni plus savants que lorsque
nous ne savions rien.
Ne pas savoir ce qu'il est venu faire sur cette terre, voilà le grand
et l'éternel tourment de l'homme. Or, il faut bien se dire que la vérité
vraie de l'univers, si nous l'apprenons quelque jour, sera
probablement assez semblable à l'une ou l'autre de ces révélations
qui, ayant l'air de nous apprendre tout, ne nous apprennent rien.
Elle aura du moins le même caractère inhumain. Il faudra bien
qu'elle soit aussi illimitée dans l'espace et le temps, aussi abyssale,
aussi étrangère à nos sens et à notre cerveau. Plus la révélation sera
immense et haute, plus elle aura chance d'être vraie; mais plus aussi
elle s'éloignera de nous, moins elle nous intéressera. Nous ne
pouvons guère espérer de sortir de ce dilemme décourageant: les
révélations, les explications ou les interprétations trop petites ne
nous satisferont point parce que nous les pressentirons insuffisantes,
et celles qui seront trop grandes passeront trop loin de nous pour
nous atteindre.
II

Il serait cependant souhaitable que cette révélation des livres


sacrés de l'Inde fût authentique et que notre science encore si
étroite, si petite, si timide et si incohérente, confirmât peu à peu,
comme du reste elle le fait chaque jour à son insu, certains points
épars dans l'immensité sans bornes de cette immémoriale vérité.
Elle aurait en tout cas, même si elle ne parvenait pas à nous
atteindre directement, l'avantage d'élargir à l'infini notre horizon plus
borné qu'on ne croit; de jalonner cet infini de repères magnifiques,
de l'animer, de le peupler, de lui donner d'admirables visages, de le
rendre vivant, sensible et presque compréhensible.
Nous savons tous que nous vivons dans l'infini; mais cet infini
pour nous n'est qu'un mot sec et nu, un vide noir et inhabitable, une
abstraction sans forme, une expression morte que notre imagination
ne ranime un moment qu'au prix d'un effort fatigant, solitaire,
inhabile, inassisté, ingrat et infructueux. En fait, nous nous tenons
cantonnés dans notre monde terrestre et dans nos petits temps
historiques, et tout au plus levons-nous parfois les yeux vers les
planètes de notre système solaire et poussons-nous notre pensée,
d'avance découragée, jusqu'aux époques nébuleuses qui
précédèrent l'arrivée de l'homme sur notre globe. De plus en plus,
délibérément, nous tournons sur nous-mêmes toute l'activité de
notre intelligence et, par une regrettable illusion d'optique, plus elle
rétrécit son champ d'action, plus nous croyons qu'elle l'approfondit.
Nos penseurs et nos philosophes, de crainte de s'égarer comme
leurs prédécesseurs, ne s'intéressent plus qu'aux aspects, aux
problèmes, aux secrets les moins contestables; mais s'ils sont les
moins contestables, ils sont aussi les moins hauts, et l'homme, en
tant qu'animal terrestre, devient le seul objet de leurs études. Les
savants, d'autre part, accumulent de petits faits, de petites
observations sous lesquelles ils étouffent et qu'ils n'osent plus
soulever ou entr'ouvrir pour y faire circuler l'air d'une loi générale ou
d'une hypothèse salutaire, tant celles qu'ils hasardèrent jusqu'à ce
jour furent successivement et pitoyablement démenties ou bafouées
par l'expérience.
Néanmoins, ils ont raison d'agir comme ils font et de continuer
leurs investigations, selon leurs étroites et sévères méthodes; mais il
est permis de constater que plus ils croient s'approcher d'une vérité
qui fuit, plus augmentent leurs incertitudes et leur désarroi, plus les
assises sur lesquelles ils fondaient leur confiance leur semblent
précaires, imaginaires et insuffisantes, et mieux ils se rendent
compte de l'incommensurable distance qui les sépare encore du
moindre secret de la vie. «Il semble, comme l'a prophétisé l'un des
plus illustres d'entre eux, le physicien anglais sir William Grove, que
le jour approche rapidement où l'on confessera que les forces que
nous connaissons ne sont que les manifestations phénoménales de
réalités au sujet desquelles nous ne savons rien, mais que les
anciens connaissaient et auxquelles ils vouaient un culte.»

III

Voilà, en effet, ce qu'on ne peut s'empêcher de penser quand on


étudie quelque peu cette révélation primitive, la sagesse d'autrefois
et ce qui en a découlé. L'homme a su plus qu'il ne sait. Il ignorait
peut-être l'énorme masse de petits détails que nous avons observés
et classés et qui nous ont permis de domestiquer certaines forces
dont il ne songeait pas à tirer parti; mais il est probable qu'il en
connaissait mieux que nous la nature, l'essence et l'origine.
La haute civilisation de l'humanité que l'histoire, en tâtonnant,
reporte à cinq ou six mille ans avant Jésus-Christ, est peut-être
beaucoup plus ancienne, et sans admettre, comme on l'a affirmé,
que les Égyptiens aient conservé des archives astronomiques durant
une période de six cent trente mille ans, on peut considérer comme
établi que leurs observations embrassaient deux cycles de
précession, deux années sidérales, soit cinquante et un mille sept
cent trente-six ans. Or, eux-mêmes n'étaient pas des initiateurs,
mais des initiés, et tiraient tout ce qu'ils savaient d'une source plus
ancienne. Il en est de même des Juifs, en ce qui concerne leurs
livres primitifs et leur Kabbale; et des Grecs, parmi lesquels tous
ceux qui réellement nous apprirent quelque chose sur l'origine, et la
constitution de l'univers et de ses éléments, sur la nature de la
divinité, de la matière et de l'esprit, tels qu'Orphée, Hésiode,
Pythagore, Anaxagore, Platon et les Néo-Platoniciens, étaient
également des initiés, c'est-à-dire des hommes qui, ayant passé par
l'Égypte ou par l'Inde, avaient puisé à la même source unique et
immémoriale. Nos religions préhistoriques, scandinaves ou
germaniques et le druidisme celte, celles de la Chine et du Japon, du
Mexique et du Pérou, malgré de nombreuses déformations, en
dérivaient pareillement; de même que notre grande métaphysique
occidentale, d'avant le matérialisme actuel, dont la vue est un peu
basse, notamment les métaphysiques de Leibnitz, de Kant, de
Schelling, de Fichte, de Hegel, s'en rapprochent et s'y abreuvent plus
ou moins à leur insu.

Il est donc certain que par les Grecs, par la Bible, par le
Christianisme qui en est un dernier écho, car l'auteur de l'Apocalypse
et saint Paul étaient des initiés, nous sommes tout imprégnés de
cette révélation, qu'il n'y en a pas, qu'il n'y en eut jamais d'autre,
qu'elle est la grande révélation humaine ou surhumaine, et que par
conséquent il serait juste et salutaire de l'étudier plus attentivement
et plus profondément qu'on ne l'a fait jusqu'à ce jour.

IV

Où est la source de cette révélation? Nous la situons en Orient


parce que c'est dans les livres sacrés de l'Inde que se trouve
presque tout ce que nous en connaissons. Mais il est à peu près
certain qu'elle est d'origine occidentale ou plutôt hyperboréenne et
remonte à ces merveilleux peuples disparus, les Atlantes, dont les
dernières colonies Protosythes florissaient il y a plus de onze mille
ans et dont l'existence n'est plus niable.
On n'a pas oublié la page célèbre de Platon: Un jour que Solon
s'entretenait avec les prêtres de Saïs sur l'histoire des temps reculés,
l'un d'eux lui dit: «O Solon, vous autres Grecs, vous êtes toujours
enfants. Il n'en est pas un seul parmi vous qui ne soit novice dans la
science de l'antiquité. Vous ignorez ce que fit la génération de héros
dont vous êtes la faible postérité… Ce que je vais vous raconter
remonte à neuf mille ans.
«Nos fastes rapportent que votre pays a résisté aux efforts d'une
puissance formidable qui, sortie de la mer Atlantique, avait envahi
une grande partie de l'Europe; car, pour lors, cette mer était
navigable. Près de ses bords était une île, vis-à-vis de l'embouchure
que vous nommez les colonnes d'Hercule. On dit que de cette île,
plus étendue que la Lydie et que l'Asie, il était facile de se rendre sur
le continent.
«Dans cette Atlantide, il y avait des rois célèbres par leur
puissance qui s'étendait sur les îles adjacentes et sur une partie du
continent. Ils régnaient, outre cela, d'un côté sur la Lydie jusqu'à
l'Égypte, et du côté de l'Europe jusqu'à la Tyrrhénie… Mais il survint
des tremblements de terre et des inondations; et dans l'espace de
vingt-quatre heures, l'Atlantide disparut.»
Ce passage du Timée est la première lueur que l'histoire
proprement dite ait projetée sur l'immense chaos des temps
antédiluviens. Les recherches et les découvertes modernes l'ont
confirmé point par point. Comme le dit Roisel, qui a consacré aux
Atlantes un livre remarquable, moins connu que ceux de Scott Elliot
et de Rudolf Steiner, et qui ne permet plus le moindre doute, «il est
prouvé que bien avant les siècles historiques, les Atlantes avaient
acquis une science merveilleuse dont l'humanité commence à peine
à reconstituer les éléments et dont les puissantes épaves se
retrouvent dans les Gaules, l'Égypte, la Perse, les Indes et la partie
centrale du continent américain. Plus de dix mille ans avant notre
ère, ils connaissaient la précession des équinoxes, les modifications
si lentes que plusieurs astres éprouvent dans leur cours et les mille
secrets de la nature. Ils avaient des procédés dont l'industrie
moderne n'a pas encore pénétré les mystères».
Il ressort de ces études que l'humanité n'éprouva jamais désastre
comparable à la disparition de l'Atlantide. Il lui faudra peut-être des
milliers d'années pour réparer cette perte et remonter au niveau
d'une civilisation qui avait sur l'origine et les mouvements de
l'univers, sur l'énergie de la matière, sur les forces inconnues de ce
monde et des autres, sur la vie d'outre-tombe, sur l'organisation
sociale et l'économie politique, comparables à celle des abeilles, des
certitudes dont nous glanons péniblement les débris dispersés. Rien
ne prouverait mieux l'inutilité de l'effort de l'homme que cette perte
inégalée, si l'on ne s'efforçait d'espérer malgré tout.
Peuple de métallurgistes prodigieux qui avaient découvert la
trempe du cuivre que nous cherchons encore, peuple d'ingénieurs
fabuleux dont la géométrie, au dire du professeur Smyth,
commençait là où finit celle d'Euclide, ils soulevaient et
transportaient à d'énormes distances, par des moyens mystérieux,
des rochers de quinze cents tonnes et semaient par le monde ces
fantastiques pierres mouvantes, appelées «pierres folles», «pierres
de vérité», blocs de cinq cent mille kilos, si habilement couchées sur
un de leurs angles qu'un enfant peut les mouvoir du doigt, tandis
que la poussée de deux cents hommes serait incapable de les
renverser et qui, géologiquement, n'appartiennent jamais au sol sur
lequel elles se trouvent. Peuple d'explorateurs qui avaient parcouru
et colonisé toute la surface de la terre, peuple de savants, de
calculateurs, d'astronomes; ils semblent avoir été avant tout des
rationalistes et des logiciens implacables, au cerveau pour ainsi dire
métallique, dont les lobes latéraux étaient beaucoup plus développés
que les nôtres. Ils n'appliquaient leurs aptitudes incomparables qu'à
l'étude des sciences exactes; et le seul but de leurs efforts était la
conquête du vrai. Mais l'étude de l'invisible, et de l'infini, sous leurs
puissants regards devient elle-même une science exacte; et l'idée
mère de leur cosmogonie, en vertu de laquelle tout sort de l'océan
de la matière cosmique ou des flots sans limites de l'éternel éther
pour y rentrer bientôt et pour en ressortir, défigurée et surchargée
de mythes innombrables par l'imagination de leurs descendants ou
de leurs colons dégénérés, est à la base de toutes les religions; et il
est peu probable que l'homme en découvre jamais une qui la vaille
et la puisse remplacer.

C'est dans les livres sacrés de l'Inde que nous trouvons les traces
les plus sûres et les plus abondantes de cette cosmogonie ou de
cette révélation.
Il y a moins d'un siècle, on ignorait à peu près totalement
l'existence de ces livres. Leurs interprètes ont pris deux routes
différentes. D'un côté, des savants, qu'on pourrait appeler officiels,
ont donné la traduction d'un certain nombre de textes qu'on pourrait
également qualifier d'officiels, textes qu'ils ne comprennent pas
toujours et que leurs lecteurs comprennent encore moins. De l'autre,
des initiés ou soi-disant tels, avec le concours d'adeptes d'une
fraternité occulte, ont proposé, de ces mêmes textes ou d'autres
plus secrets, une interprétation nouvelle et plus impressionnante. Ils
inspirent encore, à tort ou à raison, quelque méfiance. On doit
admettre l'authenticité et l'antiquité de certaines traditions, de
certains écrits primitifs et essentiels, bien qu'il soit impossible de leur
assigner une date approximative, tant ils se perdent dans les brumes
de la préhistoire. Mais ils sont à peu près incompréhensibles sans
clefs et sans commentaires, et c'est ici que commencent les doutes
et les hésitations. Un grand nombre de ces commentaires sont
également très anciens et, à leur tour, ont besoin de clefs, d'autres
paraissent plus récents, d'autres enfin semblent contemporains et le
départ est souvent malaisé entre ce qui se trouve en puissance dans
l'original et ce que les interprètes croient y trouver ou y ajoutent
plus ou moins volontairement. Or, le plus frappant, le plus grandiose
et, en tout cas, le plus clair de la doctrine réside souvent dans les
commentaires.
Il y a ensuite, comme je viens de le dire, la question des clefs,
intimement liée à la précédente. Ces clefs sont plus ou moins
maniables, s'imposent plus ou moins, paraissent parfois chimériques
ou arbitraires, ne sont livrées qu'avec d'étranges précautions, une à
une et parcimonieusement, et peuvent ouvrir plusieurs sens
superposés. Et tout cela s'accompagne de réticences bizarres, de
secrets soi-disant dangereux ou terribles, retenus au moment décisif,
de révélations qu'on prétend incommunicables avant bien des
siècles. Des portes qu'on allait franchir se referment brusquement à
l'instant qu'on entrevoyait enfin un horizon longtemps promis, et
derrière chacune d'elles se cache un initié suprême, un Maître
encore vivant, gardien sacré des derniers arcanes, qui sait tout mais
ne veut ou ne peut rien dire.
Notez, en outre, qu'une foule d'illuminés plus ou moins
intelligents, de jeunes filles et de vieilles dames déséquilibrées, de
naïfs qui adoptent d'emblée et aveuglément ce qu'ils ne
comprennent pas, de mécontents, de ratés, de vaniteux, de
roublards qui pèchent en eau trouble, en un mot la tourbe habituelle
et suspecte qui s'agglomère autour de toute doctrine, de toute
science, de tout phénomène un peu mystérieux, a discrédité ces
premières interprétations ésotériques, dont la source même n'est
pas très claire. Ajoutez enfin que l'incendie de la fameuse
bibliothèque d'Alexandrie, où s'était entassée toute la science de
l'Orient, l'anéantissement, au XVIe siècle, sous le règne mongol
d'Akbar, de milliers d'œuvres sanscrites, la destruction systématique
et impitoyable, surtout aux premiers siècles de l'Église et durant le
Moyen Age, de tout ce qui se rapportait ou faisait allusion à cette
révélation gênante et redoutée, nous ont enlevé nos meilleurs
moyens de contrôle. Les adeptes, il est vrai, affirment, d'autre part,
que les textes véritables, ainsi que les vieux commentaires qui seuls
les rendent compréhensibles, existent encore dans des cryptes
secrètes, dans des bibliothèques souterraines du Thibet ou de
l'Himalaya, aux livres plus innombrables que tous ceux que nous
possédons en Occident, et qu'ils reparaîtront dans un âge plus
éclairé. C'est possible, mais en attendant ils ne nous sont d'aucun
secours.

VI

Quoi qu'il en soit, ce que nous avons suffit à troubler


profondément, et le contrôle que permettent les fragments sauvés
de l'antiquité historique écarte absolument, quant aux éléments
essentiels, tout soupçon de fraude ou de mystification plus ou moins
récente. Au surplus, une fraude ou une mystification de ce genre ne
paraît guère possible et serait tellement géniale qu'il faudrait
l'admirer comme un phénomène presque égal à celui dont elle
voudrait donner l'illusion, et convenir que jamais l'esprit de l'homme
ne plongea plus avant dans l'infini du temps et de l'espace, dans
l'origine des choses et ne s'éleva à de pareilles hauteurs. Elle aurait
profité, cette révélation, de tout l'acquis de la science et de la
pensée d'aujourd'hui, qu'elle n'aurait pu, sur le rythme des éternités,
sur le va-et-vient du toujours devenir, sur le cycle sans fin et les
existences périodiques du moi, sur la naissance, le mouvement et
l'évolution des mondes, sur les souffles divins de l'intelligence qui les
animent, sur Maya, l'éternelle illusion de l'ignorance, sur la lutte pour
la vie, la sélection naturelle, le développement graduel et la
transformation des astres et des hommes, sur les fonctions et les
énergies de l'éther, sur la justice immortelle et infaillible, sur l'activité
intermoléculaire et fantastique de la matière, sur la nature de l'âme
et sur l'existence de l'immense puissance innommable qui gouverne
l'univers, en un mot sur toutes les énigmes qui nous assaillent et
tous les mystères qui nous accablent, nous donner des hypothèses
plus satisfaisantes, plus logiques, plus cohérentes, plus plausibles,
plus synthétiques, plus dignes de l'infini qu'elles cherchent à
embrasser et que bien souvent elles semblent étreindre.
Mais, hâtons-nous de le répéter, il ne saurait être sérieusement
question de fraude, puisque les textes ou les traditions qu'on
pourrait suspecter se trouvent corroborés par d'autres textes, les
inscriptions sacrées de l'Égypte, par exemple, que nul ne songe à
contester. Tout au plus, rencontrera-t-on quelques passages
antidatés par le zèle imprudent d'adeptes ou de commentateurs,
quelques interpolations qui ne font qu'enguirlander les grandes
lignes. Il s'agit bien, dans l'ensemble, d'une révélation qui remonte
infiniment plus haut que tout ce que nous avons appelé la
préhistoire, et dès lors il est légitime que notre étonnement n'ait plus
de bornes.

VII

Fort bien, dira-t-on, cette interprétation de l'univers, cette


anthropo-cosmogénèse est la plus haute, la plus vaste, la plus
admirable, la plus inattaquable qu'on ait jamais conçue; elle déborde
de toutes parts l'imagination et la pensée de l'homme; mais sur quoi
tout cela repose-t-il? Il n'y a là, en fin de compte, que de
magnifiques hypothèses audacieusement travesties en affirmations
magistrales, péremptoires et dogmatiques, mais qui sont toutes
invérifiables. C'est l'objection que j'ai faite moi-même, un peu
hâtivement, dans un des premiers chapitres de la Mort.
Il est, en effet, incontestable que nous ne connaîtrons pas de si
tôt, que nous ne connaîtrons peut-être jamais la vérité sur l'origine
et la fin de l'univers ni sur tous les autres problèmes que ces
affirmations résolvent. Seulement, il est curieux de constater que la
science, chaque jour, se rapproche, malgré elle, de l'une ou l'autre
de ces affirmations, et qu'elle ne peut en écarter ou démentir
aucune. Il y a telle étude du chimiste Crookes, par exemple, sur la
genèse des éléments qui, à son insu, devient nettement occultiste,
tandis que la découverte de la radio-activité de la matière reproduit
exactement la théorie des tourbillons de l'initié Anaxagore. Il en est
de même, mutatis mutandis, du rôle attribué à l'éther, dernier et
indispensable postulat de nos savants. Il en est de même des
fonctions souveraines et essentielles de certaines glandes minuscules
dont la médecine moderne commence à peine à retrouver
l'importance et qui recèlent probablement les secrets primordiaux de
la vie: la glande thyroïde qui préside à la croissance et à
l'intelligence, la glande surrénale qui régente ce muscle inconscient
qu'est le cœur et la glande pinéale, la plus mystérieuse de toutes,
qui nous met en rapport avec les mondes inconnus. Il en est encore
de même en astronomie où l'insuffisance manifeste de nos soi-disant
lois cosmiques, notamment celle de la gravitation et de la formation
des nébuleuses, pose une foule de questions auxquelles répond
seule la cosmogonie orientale. Mais ceci demanderait une longue
étude que je n'ai pas qualité pour entreprendre.
Au demeurant, rien ne nous oblige à accepter ces affirmations
comme des dogmes. Il ne s'agit pas ici d'une religion qui nous
impose sa foi aveugle, son Credo quia absurdum. Il nous est
parfaitement loisible de les considérer comme de simples
hypothèses, d'immenses, d'incomparables poèmes antédiluviens,
dont la genèse de Moïse n'est qu'un fragment défiguré. Mais, en tant
qu'hypothèses ou poèmes, il faut convenir qu'elles sont prodigieuses,
que nous n'avons rien de meilleur, rien de plus vraisemblable à leur
opposer et, qu'étant donnée leur antiquité indiscutable, leur origine
préhistorique, elles semblent réellement surhumaines.
Faut-il admettre, comme le prétendent les occultistes, qu'elles
nous viennent d'êtres supérieurs à l'homme, d'entités plus
spirituelles vivant dans des conditions inconnues, qui occupaient
notre terre ou les planètes voisines, avant notre venue; d'une
civilisation lémuro-atlantéenne qui a laissé en la mémoire des
peuples et sur le sol de notre globe, dans ses monuments
mégalithiques, des traces indélébiles? C'est fort possible, mais ici
encore nous sommes libres d'attendre les confirmations de
l'archéologie hindoue, égyptienne, chaldéenne, assyrienne et
persane, qui, sur ce point, comme sur tant d'autres, n'a pas dit son
dernier mot.
Welcome to Our Bookstore - The Ultimate Destination for Book Lovers
Are you passionate about books and eager to explore new worlds of
knowledge? At our website, we offer a vast collection of books that
cater to every interest and age group. From classic literature to
specialized publications, self-help books, and children’s stories, we
have it all! Each book is a gateway to new adventures, helping you
expand your knowledge and nourish your soul
Experience Convenient and Enjoyable Book Shopping Our website is more
than just an online bookstore—it’s a bridge connecting readers to the
timeless values of culture and wisdom. With a sleek and user-friendly
interface and a smart search system, you can find your favorite books
quickly and easily. Enjoy special promotions, fast home delivery, and
a seamless shopping experience that saves you time and enhances your
love for reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!

ebookgate.com

You might also like