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

Instant ebooks textbook Python Programming for Data Analysis 1st Edition José Unpingco download all chapters

Data

Uploaded by

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

Instant ebooks textbook Python Programming for Data Analysis 1st Edition José Unpingco download all chapters

Data

Uploaded by

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

Experience Seamless Full Ebook Downloads for Every Genre at textbookfull.

com

Python Programming for Data Analysis 1st Edition


José Unpingco

https://textbookfull.com/product/python-programming-for-
data-analysis-1st-edition-jose-unpingco/

OR CLICK BUTTON

DOWNLOAD NOW

Explore and download more ebook at https://textbookfull.com


Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.

Python for Probability Statistics and Machine Learning


José Unpingco

https://textbookfull.com/product/python-for-probability-statistics-
and-machine-learning-jose-unpingco/

textboxfull.com

Python for Probability, Statistics, and Machine Learning


2nd Edition José Unpingco

https://textbookfull.com/product/python-for-probability-statistics-
and-machine-learning-2nd-edition-jose-unpingco/

textboxfull.com

Vertically Integrated Architectures: Versioned Data


Models, Implicit Services, and Persistence-Aware
Programming 1st Edition Jos Jong
https://textbookfull.com/product/vertically-integrated-architectures-
versioned-data-models-implicit-services-and-persistence-aware-
programming-1st-edition-jos-jong/
textboxfull.com

Practical Machine Learning for Data Analysis Using Python


1st Edition Abdulhamit Subasi

https://textbookfull.com/product/practical-machine-learning-for-data-
analysis-using-python-1st-edition-abdulhamit-subasi/

textboxfull.com
Python for Data Analysis Data Wrangling with Pandas NumPy
and IPython Wes Mckinney

https://textbookfull.com/product/python-for-data-analysis-data-
wrangling-with-pandas-numpy-and-ipython-wes-mckinney/

textboxfull.com

Python for Excel A Modern Environment for Automation and


Data Analysis 1st Edition Felix Zumstein

https://textbookfull.com/product/python-for-excel-a-modern-
environment-for-automation-and-data-analysis-1st-edition-felix-
zumstein/
textboxfull.com

Python for Data Analysis Data Wrangling with pandas NumPy


and Jupyter 3rd Edition Wes Mckinney

https://textbookfull.com/product/python-for-data-analysis-data-
wrangling-with-pandas-numpy-and-jupyter-3rd-edition-wes-mckinney/

textboxfull.com

Functional Programming in R: Advanced Statistical


Programming for Data Science, Analysis and Finance 1st
Edition Thomas Mailund
https://textbookfull.com/product/functional-programming-in-r-advanced-
statistical-programming-for-data-science-analysis-and-finance-1st-
edition-thomas-mailund/
textboxfull.com

Python Data Analysis: Perform data collection, data


processing, wrangling, visualization, and model building
using Python 3rd Edition Avinash Navlani
https://textbookfull.com/product/python-data-analysis-perform-data-
collection-data-processing-wrangling-visualization-and-model-building-
using-python-3rd-edition-avinash-navlani/
textboxfull.com
José Unpingco

Python
Programming
for Data
Analysis
Python Programming for Data Analysis
José Unpingco

Python Programming
for Data Analysis
José Unpingco
University of California
San Diego
CA, USA

ISBN 978-3-030-68951-3 ISBN 978-3-030-68952-0 (eBook)


https://doi.org/10.1007/978-3-030-68952-0

© The Editor(s) (if applicable) and The Author(s), under exclusive license to Springer Nature Switzerland
AG 2021
This work is subject to copyright. All rights are solely and exclusively licensed by the Publisher, whether
the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse
of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and
transmission or information storage and retrieval, electronic adaptation, computer software, or by similar
or dissimilar methodology now known or hereafter developed.
The use of general descriptive names, registered names, trademarks, service marks, etc. in this publication
does not imply, even in the absence of a specific statement, that such names are exempt from the relevant
protective laws and regulations and therefore free for general use.
The publisher, the authors, and the editors are safe to assume that the advice and information in this book
are believed to be true and accurate at the date of publication. Neither the publisher nor the authors or
the editors give a warranty, expressed or implied, with respect to the material contained herein or for any
errors or omissions that may have been made. The publisher remains neutral with regard to jurisdictional
claims in published maps and institutional affiliations.

This Springer imprint is published by the registered company Springer Nature Switzerland AG
The registered company address is: Gewerbestrasse 11, 6330 Cham, Switzerland
To Irene, Nicholas, and Daniella, for all their
patient support.
Preface

This book grew out of notes for the ECE143 Programming for Data Analysis class
that I have been teaching at the University of California, San Diego, which is a
requirement for both graduate and undergraduate degrees in Machine Learning and
Data Science. The reader is assumed to have some basic programming knowledge
and experience using another language, such as Matlab or Java. The Python idioms
and methods we discuss here focus on data analysis, notwithstanding Python’s
usage across many other topics. Specifically, because raw data is typically a mess
and requires much work to prepare, this text focuses on specific Python language
features to facilitate such cleanup, as opposed to only focusing on particular Python
modules for this.
As with ECE143, here we discuss why things are the way they are in Python
instead of just that they are this way. I have found that providing this kind of
context helps students make better engineering design choices in their codes, which
is especially helpful for newcomers to both Python and data analysis. The text is
sprinkled with little tricks of the trade to make it easier to create readable and
maintainable code suitable for use in both production and development.
The text focuses on using the Python language itself effectively and then moves
on to key third-party modules. This approach improves effectiveness in different
environments, which may or may not have access to such third-party modules. The
Numpy numerical array module is covered in depth because it is the foundation
of all data science and machine learning in Python. We discuss the Numpy array
data structure in detail, especially its memory aspects. Next, we move on to Pandas
and develop its many features for effective and fluid data processing. Because data
visualization is key to data science and machine learning, third-party modules such
as Matplotlib are developed in depth, as well as web-based modules such as Bokeh,
Holoviews, Plotly, and Altair.
On the other hand, I would not recommend this book to someone with no
programming experience at all, but if you can do a little Python already and want to
improve by understanding how and why Python works the way it does, then this is
a good book for you.

vii
viii Preface

To get the most out of this book, open a Python interpreter and type-along with
the many code samples. I worked hard to ensure that all of the given code samples
work as advertised.

Acknowledgments I would like to acknowledge the help of Brian Granger and Fernando Perez,
two of the originators of the Jupyter Notebook, for all their great work, as well as the Python
community as a whole, for all their contributions that made this book possible. Hans Petter
Langtangen was the author of the Doconce [1] document preparation system that was used to
write this text. Thanks to Geoffrey Poore [2] for his work with PythonTeX and LATEX, both key
technologies used to produce this book.

San Diego, CA, USA José Unpingco


February, 2020

References

1. H.P. Langtangen, DocOnce markup language. https://github.com/hplgit/doconce


2. G.M. Poore, Pythontex: reproducible documents with latex, python, and more. Comput. Sci.
Discov. 8(1), 014010 (2015)
Contents

1 Basic Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Basic Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.2 Reserved Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.3 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.4 Complex Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.5 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.6 Loops and Conditionals. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.1.7 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.1.8 File Input/Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.1.9 Dealing with Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
1.1.10 Power Python Features to Master . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
1.1.11 Generators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
1.1.12 Decorators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.1.13 Iteration and Iterables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
1.1.14 Using Python Assertions to Pre-debug Code . . . . . . . . . . . . . . . 60
1.1.15 Stack Tracing with sys.settrace . . . . . . . . . . . . . . . . . . . . . . 61
1.1.16 Debugging Using IPython . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
1.1.17 Logging from Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2 Object-Oriented Programming. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.1 Properties/Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.2 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
2.3 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.4 Class Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
2.5 Class Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.6 Static Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.7 Hashing Hides Parent Variables from Children . . . . . . . . . . . . . . . . . . . . . . 76
2.8 Delegating Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.9 Using super for Delegation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.10 Metaprogramming: Monkey Patching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

ix
x Contents

2.11 Abstract Base Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80


2.12 Descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
2.13 Named Tuples and Data Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.14 Generic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
2.15 Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.15.1 Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.15.2 Singleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
2.15.3 Observer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
2.15.4 Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
3 Using Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.1 Standard Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
3.2 Writing and Using Your Own Modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
3.2.1 Using a Directory as a Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.3 Dynamic Importing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
3.4 Getting Modules from the Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
3.5 Conda Package Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
4 Numpy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.1 Dtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.2 Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
4.3 Reshaping and Stacking Numpy Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
4.4 Duplicating Numpy Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
4.5 Slicing, Logical Array Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
4.6 Numpy Arrays and Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
4.7 Numpy Memory Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
4.8 Array Element-Wise Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
4.9 Universal Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
4.10 Numpy Data Input/Output. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
4.11 Linear Algebra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
4.12 Broadcasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
4.13 Masked Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
4.14 Floating Point Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
4.15 Advanced Numpy dtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
5 Pandas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
5.1 Using Series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
5.2 Using DataFrame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
5.3 Reindexing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
5.4 Deleting Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
5.5 Advanced Indexing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
5.6 Broadcasting and Data Alignment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
5.7 Categorical and Merging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Contents xi

5.8 Memory Usage and dtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143


5.9 Common Operations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
5.10 Displaying DataFrames. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
5.11 Multi-index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
5.12 Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
5.13 Data Files and Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
5.14 Customizing Pandas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
5.15 Rolling and Filling Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
6 Visualizing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
6.1 Matplotlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
6.1.1 Setting Defaults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
6.1.2 Legends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
6.1.3 Subplots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
6.1.4 Spines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
6.1.5 Sharing Axes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
6.1.6 3D Surfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
6.1.7 Using Patch Primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
6.1.8 Patches in 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
6.1.9 Using Transformations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
6.1.10 Annotating Plots with Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
6.1.11 Annotating Plots with Arrows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
6.1.12 Embedding Scalable and Non-scalable Subplots . . . . . . . . . . . 173
6.1.13 Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
6.1.14 Using Paths Directly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
6.1.15 Interacting with Plots Using Sliders . . . . . . . . . . . . . . . . . . . . . . . . 179
6.1.16 Colormaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
6.1.17 Low-Level Control Using setp and getp . . . . . . . . . . . . . . . 183
6.1.18 Interacting with Matplotlib Figures . . . . . . . . . . . . . . . . . . . . . . . . . 183
6.1.19 Keyboard Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
6.1.20 Mouse Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
6.2 Seaborn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
6.2.1 Automatic Aggregation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
6.2.2 Multiple Plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
6.2.3 Distribution Plots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
6.3 Bokeh. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
6.3.1 Using Bokeh Primitives. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
6.3.2 Bokeh Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
6.3.3 Bokeh Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
6.4 Altair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
6.4.1 Detailing Altair. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215
6.4.2 Aggregations and Transformations. . . . . . . . . . . . . . . . . . . . . . . . . . 217
6.4.3 Interactive Altair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
6.5 Holoviews . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
6.5.1 Dataset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
xii Contents

6.5.2 Image Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232


6.5.3 Tabular Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
6.5.4 Customizing Interactivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
6.5.5 Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
6.5.6 Pandas Integration with hvplot . . . . . . . . . . . . . . . . . . . . . . . . . . 237
6.5.7 Network Graphs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
6.5.8 Holoviz Panel for Dashboards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
6.6 Plotly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
Chapter 1
Basic Programming

1.1 Basic Language

Before we get into the details, it is a good idea to get a high-level orientation to
Python. This will improve your decision-making later regarding software develop-
ment for your own projects, especially as these get bigger and more complex. Python
grew out of a language called ABC, which was developed in the Netherlands in the
1980s as an alternative to BASIC to get scientists to utilize microcomputers, which
were new at the time. The important impulse was to make non-specialist scientists
able to productively utilize these new computers. Indeed, this pragmatic approach
continues to this day in Python which is a direct descendent of the ABC language.
There is a saying in Python—come for the language, stay for the community.
Python is an open source project that is community driven so there is no corporate
business entity making top-down decisions for the language. It would seem that such
an approach would lead to chaos but Python has benefited over many years from
the patient and pragmatic leadership of Guido van Rossum, the originator of the
language. Nowadays, there is a separate governance committee that has taken over
this role since Guido’s retirement. The open design of the language and the quality
of the source code has made it possible for Python to enjoy many contributions from
talented developers all over the world over many years, as embodied by the richness
of the standard library. Python is also legendary for having a welcoming community
for newcomers so it is easy to find help online for getting started with Python.
The pragmatism of the language and the generosity of the community have long
made Python a great way to develop web applications. Before the advent of data
science and machine learning, upwards of 80% of the Python community were web
developers. In the last five years (at the time of this writing), the balance is tilted to
an almost even split between web developers and data scientists. This is the reason
you find a lot of web protocols and technology in the standard library.
Python is an interpreted language as opposed to a compiled language like C
or FORTRAN. Although both cases start with a source code file, the compiler

© The Editor(s) (if applicable) and The Author(s), under exclusive license 1
to Springer Nature Switzerland AG 2021
J. Unpingco, Python Programming for Data Analysis,
https://doi.org/10.1007/978-3-030-68952-0_1
2 1 Basic Programming

examines the source code end-to-end and produces an executable that is linked to
system-specific library files. Once the executable is created, there is no longer any
need for the compiler. You can just run the executable on the system. On the other
hand, an interpreted language like Python you must always have a running Python
process to execute the code. This is because the Python process is an abstraction on
the platform it is running on and thus must interpret the instructions in the source
code to execute them on the platform. As the intermediary between the source
code on the platform, the Python interpreter is responsible for the platform specific
issues. The advantage of this is that source code can be run on different platforms as
long as there is a working Python interpreter on each platform. This makes Python
source codes portable between platforms because the platform specific details are
handled by the respective Python interpreters. Portability between platforms was
a key advantage of Python, especially in the early days. Going back to compiled
languages, because the platform specific details are embedded in the executable, the
executable is tied to a specific platform and to those specific libraries that have been
linked into the executable. This makes these codes are less portable than Python,
but because the compiler is able to link to the specific platform it has the option
to exploit platform- specific level optimizations and libraries. Furthermore, the
compiler can study the source code file and apply compiler-level optimizations that
accelerate the resulting executable. In broad strokes, those are the key differences
between interpreted and compiled languages. We will later see that there are many
compromises between these two extremes for accelerating Python codes.
It is sometimes said that Python is slow as compared to compiled languages,
and pursuant to the differences we discussed above, that may be expected, but it
is really a question of where the clock starts. If you start the clock to account for
developer time, not just code runtime, then Python is clearly faster, just because
the development iteration cycle does not require a tedious compile and link step.
Furthermore, Python is just simpler to use than compiled languages because so
many tricky elements like memory management are handled automatically. Pythons
quick turnaround time is a major advantage for product development, which requires
rapid iteration. On the other hand, codes that are compute-limited and must run
on specialized hardware are not good use-cases for Python. These include solving
systems of parallel differential equations simulating large-scale fluid mechanics or
other large-scale physics calculations. Note that Python is used in such settings but
mainly for staging these computations or postprocessing the resulting data.

1.1.1 Getting Started

Your primary interface to the Python interpreter is the commandline. You can type
in python in your terminal you should see something like the following,
Python 3.7.3 (default, Mar 27 2019, 22:11:17)
[GCC 7.3.0] :: Anaconda, Inc. on linux
1.1 Basic Language 3

Type "help", "copyright", "credits" or "license" for more


→ information.
>>>

There is a lot of useful information including the version of Python and its
provenance. This matters because sometimes the Python interpreter is compiled to
allow fast access to certain preferred modules (i.e., math module). We will discuss
this more when we talk about Python modules.

1.1.2 Reserved Keywords

Although Python will not stop you, do not use these as variable or function names.
and del from not while
as elif global or with
assert else if pass yield
break except import print
class exec in raise
continue finally is return
def for lambda try

nor these neither


abs all any ascii bin bool breakpoint bytearray bytes callable
chr classmethod compile complex copyright credits delattr
dict dir display divmod enumerate eval exec filter float
format frozenset getattr globals hasattr hash help hex id
input int isinstance issubclass iter len list locals map max
memoryview min next object oct open ord pow print property
range repr reversed round set setattr slice sorted
staticmethod str sum super tuple type vars zip

For example, a common mistake is to assign sum=10, not realizing that now the
sum() Python function is no longer available.

1.1.3 Numbers

Python has common-sense number-handling capabilities. The comment character is


the hash (#) symbol.
>>> 2+2
4
>>> 2+2 # and a comment on the same line as code
4
>>> (50-5*6)/4
5.0

Note that division in Python 2 is integer-division and in Python 3 it is floating


point division with the // symbol providing integer-division. Python is dynamically
4 1 Basic Programming

typed, so we can do the following assignments without declaring the types of


width and height.
>>> width = 20
>>> height = 5*9
>>> width * height
900
>>> x = y = z = 0 # assign x, y and z to zero
>>> x
0
>>> y
0
>>> z
0
>>> 3 * 3.75 / 1.5
7.5
>>> 7.0 / 2 # float numerator
3.5
>>> 7/2
3.5
>>> 7 // 2 # double slash gives integer division
3

It is best to think of assignments as labeling values in memory. Thus, width is a


label for the number 20. This will make more sense later.1 Since Python 3.8, the
walrus assignment operator allows the assignment itself to have the value of the
assignee, as in the following,
>>> print(x:=10)
10
>>> print(x)
10

The operator has many other subtle uses and was introduced to improve readability
in certain situations. You can also cast among the numeric types in a common-sense
way:
>>> int(1.33333)
1
>>> float(1)
1.0
>>> type(1)
<class 'int'>
>>> type(float(1))
<class 'float'>

Importantly, Python integers are of arbitrary length and can handle extremely large
integers. This is because they are stored as a list of digits internally. This means that
they are slower to manipulate than Numpy integers which have fixed bit-lengths,
provided that the integer can fit into allocated memory.

1 Notehttp://www.pythontutor.com is a great resource for exploring how variables are assigned in


Python.
1.1 Basic Language 5

Programming Tip: IPython


The default Python interpreter is useful and you should be familiar with it
but the IPython interpretera is a useful extension that provides features like
sophisticated tab-completion and many other conveniences that make it easier
to work with Python in the terminal.
a
See http://github.com/ipython/ipython for the latest on how to get started with IPython.

1.1.4 Complex Numbers

Python has rudimentary support for complex numbers.


>>> 1j * 1J
(-1+0j)
>>> 1j * complex(0,1)
(-1+0j)
>>> 3+1j*3
(3+3j)
>>> (3+1j)*3
(9+3j)
>>> (1+2j)/(1+1j)
(1.5+0.5j)
>>> a=1.5+0.5j
>>> a.real # the dot notation gets an attribute
1.5
>>> a.imag
0.5
>>> a=3.0+4.0j
>>> float(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float
>>> a.real
3.0
>>> a.imag
4.0
>>> abs(a) # sqrt(a.real**2 + a.imag**2)
5.0
>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> # the underscore character is the last evaluated result
>>> round(_, 2) # the underscore character is the last evaluated
→ result
113.06
6 1 Basic Programming

We typically use Numpy for complex numbers, though.

1.1.5 Strings

String-handling is very well developed and highly optimized in Python. We just


cover the main points here. First, single or double quotes define a string and there is
no precedence relationship between single and double quotes.
>>> 'spam eggs'
'spam eggs'
>>> 'doesn\'t' # backslash defends single quote
"doesn't"
>>> "doesn't"
"doesn't"
>>> '"Yes," he said.'
'"Yes," he said.'
>>> "\"Yes,\" he said."
'"Yes," he said.'
>>> '"Isn\'t," she said.'
'"Isn\'t," she said.'

Python strings have C-style escape characters for newlinewsnewlines, tabs, etc.
String literals defined this way are by default encoded using UTF-8 instead of
ASCII, as in Python 2. The triple single (’) or triple double quote (") denotes a
block with embedded newlines or other quotes. This is particularly important for
function documentation docstrings that we will discussed later.
>>> print( '''Usage: thingy [OPTIONS]
... and more lines
... here and
... here
... ''')
Usage: thingy [OPTIONS]
and more lines
here and
here

Strings can be controlled with a character before the single or double quote. For
example, see the comments (#) below for each step,
>>> # the 'r' makes this a 'raw' string
>>> hello = r"This long string contains newline characters \n, as
→ in C"
>>> print(hello)
This long string contains newline characters \n, as in C
>>> # otherwise, you get the newline \n acting as such
>>> hello = "This long string contains newline characters \n, as
→ in C"
>>> print(hello)
This long string contains newline characters
, as in C
1.1 Basic Language 7

>>> u'this a unicode string μ ±' # the 'u' makes it a unicode


→ string for Python2
'this a unicode string μ ±'
>>> 'this a unicode string μ ±' # no 'u' in Python3 is still
→ unicode string
'this a unicode string μ ±'
>>> u'this a unicode string \xb5 \xb1' # using hex-codes
'this a unicode string μ ±'

Note that a f-string evaluates (i.e., interpolates) the Python variables in the
current scope,
>>> x = 10
>>> s = f'{x}'
>>> type(s)
<class 'str'>
>>> s
'10'

Beware that an f-string is not resolved until run-time because it has to resolve
the embedded variables. This means that you cannot use f-strings as docstrings.
Importantly, Python strings are immutable which means that once a string is created,
it cannot be changed in-place. For example,
>>> x = 'strings are immutable '
>>> x[0] = 'S' # not allowed!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

This means you have to create new strings to make this kind of change.
Strings vs Bytes In Python 3, the default string encoding for string literals is UTF-
8. The main thing to keep in mind is that bytes and strings are now distinct objects,
as opposed to both deriving from basestring in Python 2. For example, given
the following unicode string,
>>> x='Ø'
>>> isinstance(x,str) # True
True
>>> isinstance(x,bytes) # False
False
>>> x.encode('utf8') # convert to bytes with encode
b'\xc3\x98'

Note the distinction between bytes and strings. We can convert bytes to strings using
decode,
>>> x=b'\xc3\x98'
>>> isinstance(x,bytes) # True
True
>>> isinstance(x,str) # False
False
>>> x.decode('utf8')
'Ø'
8 1 Basic Programming

An important consequence is that you cannot append strings and bytes as in the
following: u"hello"+b"goodbye". This used to work fine in Python 2 because
bytes would automatically be decoded using ASCII, but this no longer works in
Python 3. To get this behavior, you have to explicitly decode/encode. For
example,
>>> x=b'\xc3\x98'
>>> isinstance(x,bytes) # True
True
>>> y='banana'
>>> isinstance(y,str) # True
True
>>> x+y.encode()
b'\xc3\x98banana'
>>> x.decode()+y
'Øbanana'

Slicing Strings Python is a zero-indexed language (like C). The colon (:) character
denotes .
>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
'<HelpAHelpAHelpAHelpAHelpA>'
>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'
>>> word[-1] # The last character
'A'
>>> word[-2] # The last-but-one character
'p'
>>> word[-2:] # The last two characters
'pA'
>>> word[:-2] # Everything except the last two characters
'Hel'

String Operations Some basic numerical operations work with strings.


>>> 'hey '+'you' # concatenate with plus operator
'hey you'
>>> 'hey '*3 # integer multiplication duplicates strings
'hey hey hey '
>>> ('hey ' 'you') # using parentheses without separating comma
'hey you'

Python has a built-in and very powerful regular expression module (re) for string
manipulations. String substitution creates new strings.
>>> x = 'This is a string'
>>> x.replace('string','newstring')
'This is a newstring'
>>> x # x hasn't changed
'This is a string'
1.1 Basic Language 9

Formatting Strings There are so many ways to format strings in Python, but here
is the simplest that follows C-language sprintf conventions in conjunction with
the modulo operator %.
>>> 'this is a decimal number %d'%(10)
'this is a decimal number 10'
>>> 'this is a float %3.2f'%(10.33)
'this is a float 10.33'
>>> x = 1.03
>>> 'this is a variable %e' % (x) # exponential format
'this is a variable 1.030000e+00'

Alternatively, you can just join them using +,


>>> x = 10
>>> 'The value of x = '+str(x)
'The value of x = 10'

You can format using dictionaries as in the following,


>>> data = {'x': 10, 'y':20.3}
>>> 'The value of x = %(x)d and y = %(y)f'%(data)
'The value of x = 10 and y = 20.300000'

You can use the format method on the string,


>>> x = 10
>>> y = 20
>>> 'x = {0}, y = {1}'.format(x,y)
'x = 10, y = 20'

The advantage of format is you can reuse the placeholders as in the following,
>>> 'x = {0},{1},{0}; y = {1}'.format(x,y)
'x = 10,20,10; y = 20'

And also the f-string method we discussed above.

Programming Tip: Python 2 Strings


In Python 2, the default string encoding was 7-bit ASCII. There was no
distinction between bytes and strings. For example, you could read from a
binary-encoded JPG file as in the following,
with open('hour_1a.jpg','r') as f:
x = f.read()

This works fine in Python 2 but throws a UnicodeDecodeError error in


Python 3. To fix this in Python 3, you have to read using the rb binary mode
instead of just the r file mode.

Basic Data Structures Python provides many powerful data structures. The two
most powerful and fundamental are the list and dictionary. Data structures and
10 1 Basic Programming

algorithms go hand-in-hand. If you do not understand data structures, then you


cannot effectively write algorithms and vice versa. Fundamentally, data structures
provide guarantees to the programmer that will be fulfilled if the data structures are
used in the agreed-upon manner. These guarantees are known as the invariants for
the data structure.
Lists The list is an order-preserving general container that implements the
sequence data structure. The invariant for the list is that indexing a non-empty list
will always give you the next valid element in order. Indeed, the list is Python’s
primary ordered data structure. This means that if you have a problem where order
is important, then you should be thinking about the list data structure. This will
make sense with following examples.
>>> mix = [3,'tree',5.678,[8,4,2]] # can contain sublists
>>> mix
[3, 'tree', 5.678, [8, 4, 2]]
>>> mix[0] # zero-indexed Python
3
>>> mix[1] # indexing individual elements
'tree'
>>> mix[-2] # indexing from the right, same as strings
5.678
>>> mix[3] # get sublist
[8, 4, 2]
>>> mix[3][1] # last element is sublist
4
>>> mix[0] = 666 # lists are mutable
>>> mix
[666, 'tree', 5.678, [8, 4, 2]]
>>> submix = mix[0:3] # creating sublist
>>> submix
[666, 'tree', 5.678]
>>> switch = mix[3] + submix # append two lists with plus
>>> switch
[8, 4, 2, 666, 'tree', 5.678]
>>> len(switch) # length of list is built-in function
6
>>> resize=[6.45,'SOFIA',3,8.2E6,15,14]
>>> len(resize)
6
>>> resize[1:4] = [55] # assign slices
>>> resize
[6.45, 55, 15, 14]
>>> len(resize) # shrink a sublist
4
>>> resize[3]=['all','for','one']
>>> resize
[6.45, 55, 15, ['all', 'for', 'one']]
>>> len(resize)
4
>>> resize[4]=2.87 # cannot append this way!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> temp = resize[:3]
1.1 Basic Language 11

>>> resize = resize + [2.87] # add to list


>>> resize
[6.45, 55, 15, ['all', 'for', 'one'], 2.87]
>>> len(resize)
5
>>> del resize[3] # delete item
>>> resize
[6.45, 55, 15, 2.87]
>>> len(resize) # shorter now
4
>>> del resize[1:3] # delete a sublist
>>> resize
[6.45, 2.87]
>>> len(resize) # shorter now
2

Programming Tip: Sorting Lists


The built-in function sorted sorts lists,
>>> sorted([1,9,8,2])
[1, 2, 8, 9]

Lists can also be sorted in-place using the sort() list method,
>>> x = [1,9,8,2]
>>> x.sort()
>>> x
[1, 2, 8, 9]

Both of these use the powerful Timsort algorithm. Later, we will see more
variations and uses for these sorting functions.

Now that we have a feel for how to index and use lists, let us talk about the invariant
that it provides: as long as you index a list within its bounds, it provides the next
ordered element of the list. For example,
>>> x = ['a',10,'c']
>>> x[1] # return 10
10
>>> x.remove(10)
>>> x[1] # next element
'c'

Notice that the list data structure filled in the gap after removing 10. This is extra
work that the list data structure did for you without explicitly programming. Also,
list elements are accessible via integer indices and integers have a natural ordering
and thus so does the list. The work of maintaining the invariant does not come for
free, however. Consider the following,
>>> x = [1,3,'a']
>>> x.insert(0,10) # insert at beginning
12 1 Basic Programming

>>> x
[10, 1, 3, 'a']

Seem harmless? Sure, for small lists, but not so for large lists. This is because
to maintain the invariant the list has to scoot (i.e., memory copy) the remaining
elements over to the right to accommodate the new element added at the beginning.
Over a large list with millions of elements and in a loop, this can take a substantial
amount of time. This is why the default append() and pop() list methods work
at the tail end of the list, where there is no need to scoot items to the right.
Tuples Tuples are another general purpose sequential container in Python, very
similar to lists, but these are immutable. Tuples are delimited by commas (parenthe-
ses are grouping symbols). Here are some examples,
>>> a = 1,2,3 # no parenthesis needed!
>>> type(a)
<class 'tuple'>
>>> pets=('dog','cat','bird')
>>> pets[0]
'dog'
>>> pets + pets # addition
('dog', 'cat', 'bird', 'dog', 'cat', 'bird')
>>> pets*3
('dog', 'cat', 'bird', 'dog', 'cat', 'bird', 'dog', 'cat', 'bird')
>>> pets[0]='rat' # assignment not work!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

It may seem redundant to have tuples which behave in terms of their indexing like
lists, but the key difference is that tuples are immutable, as the last line above shows.
The key advantage of immutability is that it comes with less overhead for Python
memory management. In this sense, they are lighter weight and provide stability for
codes that pass tuples around. Later, we will see this for function signatures, which
is where the major advantages of tuples arise.

Programming Tip: Understanding List Memory


Python’s id function shows an integer corresponding to the internal reference
for a given variable. Earlier, we suggested considering variable assignment as
labeling because internally Python works with a variable’s id, not its variable
name/label.
>>> x = y = z = 10.1100
>>> id(x) # different labels for same id
140271927806352
>>> id(y)
140271927806352
>>> id(z)
140271927806352

(continued)
1.1 Basic Language 13

This is more consequential for mutable data structures like lists. Consider the
following,
>>> x = y = [1,3,4]
>>> x[0] = 'a'
>>> x
['a', 3, 4]
>>> y
['a', 3, 4]
>>> id(x),id(y)
(140271930505344, 140271930505344)

Because x and y are merely two labels for the same underlying list, changes to
one of the labels affects both lists. Python is inherently stingy about allocating
new memory so if you want to have two different lists with the same content,
you can force a copy as in the following,
>>> x = [1,3,4]
>>> y = x[:] # force copy
>>> id(x),id(y) # different ids now!
(140271930004160, 140271929640448)
>>> x[1] = 99
>>> x
[1, 99, 4]
>>> y # retains original data
[1, 3, 4]

Tuple Unpacking Tuples unpack assignments in order as follows:,


>>> a,b,c = 1,2,3
>>> a
1
>>> b
2
>>> c
3

Python 3 can unpack tuples in chunks using the * operator,


>>> x,y,*z = 1,2,3,4,5
>>> x
1
>>> y
2
>>> z
[3, 4, 5]

Note how the z variable collected the remaining items in the assignment. You can
also change the order of the chunking,
>>> x,*y,z = 1,2,3,4,5
>>> x
1
14 1 Basic Programming

>>> y
[2, 3, 4]
>>> z
5

This unpacking is sometimes called de-structuring, or splat, in case you read this
term elsewhere.
Dictionaries Python dictionaries are central to Python because many other ele-
ments (e.g., functions, classes) are built around them. Effectively programming
Python means using dictionaries effectively. Dictionaries are general containers that
implement the mapping data structure, which is sometimes called a hash table or
associative array. Dictionaries require a key/value pair, which maps the key to the
value.
>>> x = {'key': 'value'}

The curly braces and the colon make the dictionary. To retrieve the value from the
x dictionary, you must index it with the key as shown,
>>> x['key']
'value'

Let us get started with some basic syntax.


>>> x={'play':'Shakespeare','actor':'Wayne','direct':'Kubrick',
... 'author':'Hemmingway','bio':'Watson'}

>>> len(x) # number of key/value pairs


5
>>> x['pres']='F.D.R.' # assignment to key 'pres'
>>> x
{'play': 'Shakespeare', 'actor': 'Wayne', 'direct': 'Kubrick',
→ 'author': 'Hemmingway', 'bio': 'Watson', 'pres': 'F.D.R.'}
>>> x['bio']='Darwin' # reassignment for 'bio' key
>>> x
{'play': 'Shakespeare', 'actor': 'Wayne', 'direct': 'Kubrick',
→ 'author': 'Hemmingway', 'bio': 'Darwin', 'pres': 'F.D.R.'}
>>> del x['actor'] # delete key/value pair
>>> x
{'play': 'Shakespeare', 'direct': 'Kubrick', 'author':
→ 'Hemmingway', 'bio': 'Darwin', 'pres': 'F.D.R.'}

Dictionaries can also be created with the dict built-in function,


>>> # another way of creating a dict
>>> x=dict(key='value',
... another_key=1.333,
... more_keys=[1,3,4,'one'])
>>> x
{'key': 'value', 'another_key': 1.333, 'more_keys': [1, 3, 4,
→ 'one']}
>>> x={(1,3):'value'} # any immutable type can be a valid key
>>> x
{(1, 3): 'value'}
>>> x[(1,3)]='immutables can be keys'
1.1 Basic Language 15

As generalized containers, dictionaries can contain other dictionaries or lists or other


Python types.

Programming Tip: Unions of Dictionaries


What if you want to create a union of dictionaries in one- line?
>>> d1 = {'a':1, 'b':2, 'c':3}
>>> d2 = {'A':1, 'B':2, 'C':3}
>>> dict(d1,**d2) # combo of d1 and d2
{'a': 1, 'b': 2, 'c': 3, 'A': 1, 'B': 2, 'C': 3}
>>> {**d1,**d2} # without dict function
{'a': 1, 'b': 2, 'c': 3, 'A': 1, 'B': 2, 'C': 3}

Pretty slick.

The invariant that the dictionary provides is that as long as you provide a valid key,
then it will always retrieve the corresponding value; or, in the case of assignment,
store the value reliably. Recall that lists are ordered data structures in the sense that
when elements are indexed, the next element can be found by a relative offset from
the prior one. This means that these elements are laid out contiguously in memory.
Dictionaries do not have this property because they will put values wherever they
can find memory, contiguous or not. This is because dictionaries do not rely upon
relative offsets for indexing, they rely instead on a hash function. Consider the
following,
>>> x = {0: 'zero', 1: 'one'}
>>> y = ['zero','one']
>>> x[1] # dictionary
'one'
>>> y[1] # list
'one'

Indexing both variables looks notationally the same in both cases, but the process
is different. When given a key, the dictionary computes a hash function and the
stores the value at a memory location based upon the hash function. What is a hash
function? A hash function takes an input and is designed to return, with very high
probability, a value that is unique to the key. In particular, this means that two keys
cannot have the same hash, or, equivalently, cannot store different values in the
same memory location. Here are two keys which are almost identical, but have very
different hashes.
>>> hash('12345')
3973217705519425393
>>> hash('12346')
3824627720283660249

All this is with respect to probability, though. Because memory is finite, it could
happen that the hash function produces values that are the same. This is known
as a hash collision and Python implements fallback algorithms to handle this
16 1 Basic Programming

case. Nonetheless, as memory becomes scarce, especially on a small platform, the


struggle to find suitable blocks of memory can be noticeable if your code uses many
large dictionaries.
As we discussed before, inserting/removing elements from the middle of a list
causes extra memory movement as the list maintains its invariant but this does
not happen for dictionaries. This means that elements can be added or removed
without any extra memory overhead beyond the cost of computing the hash function
(i.e., constant-time lookup). Thus, dictionaries are ideal for codes that do not need
ordering. Note that since Python 3.6+, dictionaries are ordered in the sense of the
order in which items were inserted to the dictionary. In Python 2.7, this was known
as collections.OrderedDict but has since become the default in Python
3.6+.
Now that we have a good idea of how dictionaries work, consider the inputs to
the hash function: the keys. We have mainly used integers and strings for keys, but
any immutable type can also be used, such as a tuple,
>>> x= {(1,3):10, (3,4,5,8):10}

However, if you try to use a mutable type as a key,


>>> a = [1,2]
>>> x[a]= 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Let us think about why this happens. Remember that the hash function guarantees
that when given a key it will always be able to retrieve the value. Suppose that it
were possible use mutable keys in dictionaries. In the above code, we would have
hash(a) -> 132334, as an example, and let us suppose the 10 value is inserted
in that memory slot. Later in the code, we could change the contents of a as in
a[0]=3. Now, because the hash function is guaranteed to produce different outputs
for different inputs, the hash function output would be different from 132334 and
thus the dictionary could not retrieve the corresponding value, which would violate
its invariant. Thus we have arrived at a contradiction that explains why dictionary
keys must be immutable.
Sets Python provides mathematical sets and corresponding operations with the
set() data structure, which are basically dictionaries without values.
>>> set([1,2,11,1]) # union-izes elements
{1, 2, 11}
>>> set([1,2,3]) & set([2,3,4]) # bitwise intersection
{2, 3}
>>> set([1,2,3]) and set([2,3,4])
{2, 3, 4}
>>> set([1,2,3]) ^ set([2,3,4]) # bitwise exclusive OR
{1, 4}
>>> set([1,2,3]) | set([2,3,4]) # OR
{1, 2, 3, 4}
>>> set([ [1,2,3],[2,3,4] ]) # no sets of lists
1.1 Basic Language 17

(without more work)


Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Note that since Python 3.6+, keys can be used as set objects, as in the following,
>>> d = dict(one=1,two=2)
>>> {'one','two'} & d.keys() # intersection
{'one', 'two'}
>>> {'one','three'} | d.keys() # union
{'one', 'two', 'three'}

This also works for dictionary items if the values are hashable,
>>> d = dict(one='ball',two='play')
>>> {'ball','play'} | d.items()
{'ball', 'play', ('one', 'ball'), ('two', 'play')}

Once you create a set, you can add individual elements or remove them as follows:,
>>> s = {'one',1,3,'10'}
>>> s.add('11')
>>> s
{1, 3, 'one', '11', '10'}
>>> s.discard(3)
>>> s
{1, 'one', '11', '10'}

Remember sets are not ordered and you cannot directly index any of the constituent
items. Also, the subset() method is for a proper subset not a partial subset. For
example,
>>> a = {1,3,4,5}
>>> b = {1,3,4,5,6}
>>> a.issubset(b)
True
>>> a.add(1000)
>>> a.issubset(b)
False

And likewise for issuperset. Sets are optimal for fast lookups in Python, as in
the following,
>>> a = {1,3,4,5,6}
>>> 1 in a
True
>>> 11 in a
False

which works really fast, even for large sets.

1.1.6 Loops and Conditionals

There are two primary looping constructs in Python: the for loop and the while
loop. The syntax of the for loop is straightforward:
18 1 Basic Programming

>>> for i in range(3):


... print(i)
...
0
1
2

Note the colon character at the end. This is your hint that the next line should be
indented. In Python, blocks are denoted by whitespace indentation (four spaces
is recommended) which makes the code more readable anyway. The for loop
iterates over items that provided by the iterator, which is the range(3) list
in the above example. Python abstracts the idea of iterable out of the looping
construction so that some Python objects are iterable all by themselves and are just
waiting for an iteration provider like a for or while loop to get them going.
Interestingly, Python has an else clause, which is used to determine whether or
not the loop exited with a break3 or not.
>>> for i in [1,2,3]:
... if i>20:
... break # won't happen
... else:
... print('no break here!')
...
no break here!

The else block is only executed when the loop terminates without breaking.
The while loop has a similar straightforward construct:
>>> i = 0
>>> while i < 3:
... i += 1
... print(i)
...
1
2
3

This also has a corresponding optional else block. Again, note that the presence
of the colon character hints at indenting the following line. The while loop will
continue until the boolean expression (i.e., i<10) evaluates False. Let us consider
boolean and membership in Python.
Logic and Membership Python is a truthy language in the sense that things are
true except for the following:
• None
• False
• zero of any numeric type, for example, 0, 0L, 0.0, 0j.
• any empty sequence, for example, ”, (), [].

3 There is also a continue statement which will jump to the top of the for or while loop.
Other documents randomly have
different content
— Onko joku ollut kenraalin puheilla?

— Oli ruotsalainen upseeri, mutta hän on jo lähtenyt matkaansa


minkä vain hevosen kaviot kestivät.

— Hyvä on! — sanoi Kuklinowski. Sitten hän kääntyi Kmicicin


puoleen:

— Jäähdyttelehän nyt kuuman päälle, ystäväiseni! Tulen pian


takaisin, ja sitten puhelemme taas!

— Mitä vangille tehdään? — kysyi yksi sotamiehistä.

— Antaa olla noin! Tulen kohta takaisin. Yksi teistä lähtee


mukaani!

Eversti poistui ja hänen jäljessään se sotamies, joka oli istunut


orrella. Kolme jäi jäljelle, mutta kohta tuli kolme muuta riiheen.

— Voitte mennä nukkumaan! — sanoi se, joka oli tuonut


Kuklinowskille
Müllerin käskyn. — Eversti käski meidän vartioida.

Kmicic hätkähti kuullessaan tuon äänen. Se tuntui tutulta.

— Jäämme mieluummin, — sanoi yksi: Kuklinowskin tuomista


sotamiehistä, — katsellaksemme kummaa, sillä semmoista…

Hänen puheensa katkesi äkkiä. Kaamea korahdus kuului hänen


kurkustaan.
Hän ojensi kätensä ja kaatui selälleen kuin ukkosen iskemänä.

Samassa kuului huuto »Pehmittäkää!», ja muut kaksi äsken


saapuneista hyökkäsivät kuin ilvekset kahden aikaisemmin tulleen
kimppuun. Syntyi lyhyt, mutta kamala taistelu palavan tervan
liekkien valossa. Hetken kuluttua kaatui kaksi miestä raskaasti
maahan, sekunnin ajan kuului korinaa, sitten taas kajahti se ääni,
joka Kmicicistä äsken oli tuntunut tutulta:

— Teidän armonne, se olen minä, Kiemlicz, ja minun poikani! Jo


aamusta asti olemme odottaneet tilaisuutta!

Ja poikiinsa kääntyen ukko sanoi:

— No, lurjukset, päästäkää herra eversti irti, pian!

Ennenkuin Kmicic ennätti tointua pökerryksestään, olivat Kosman


ja Damianin pörröiset päät hänen vierellään ja hänet vapautettiin
siteistään. Kmicic seisoi taas omilla jaloillaan, huojui ja sai vaivoin
änkytetyksi:

— Tekö?… Kiitos!

— Me tässä olemme! — vastasi ukko. — Pyhä Jumalan äiti!


Pukeutukaa, teidän armonne!… Pian!

Ja hän alkoi antaa Kmicicille vaatteita.

— Hevoset ovat oven takana! — sanoi hän. — Tie on vapaa. Siellä


on kyllä vahteja, mutta kyllähän ne meidät päästävät, kun tiedämme
tunnussanan. Kuinka teidän armonne voi?

— Kuvettani on poltettu, mutta ei pahasti. Jalkani tuntuvat


heikoilta…

— Juokaa tästä paloviinaa, teidän armonne! Kmicic tarttui


halukkaasti pulloon, jonka ukko hänelle ojensi, ja ryypättyään siitä
sanoi:

— Olen läpivilustunut. Nyt on jo parempi.

— Satulassa teidän armonne lämpenee. Hevoset odottavat.

— Minun on nyt paljon parempi, — toisti Kmicic. — Hiukan polttaa


kuvetta, mutta ei se mitään!.. Paljon parempi on oloni!

Hän istahti viljalaarin reunalle.

Hetkisen kuluttua hän todellakin oli entisissä voimissaan ja katseli


virkeästi kolmen Kiemliczin kasvoihin, joita palavan tervan keltaiset
liekit valaisivat.

Ukko astui hänen eteensä:

— Teidän armonne! Nyt on kiire! Hevoset ovat valmiina.

Mutta Andrzejssa heräsi taas eloon entinen Kmicic.

— Ei! — huudahti hän äkkiä. — Nyt minä odotan tuota petturia!

Kiemliczit katsoivat toisiinsa hämmästyneinä, mutta eivät


puhuneet sanaakaan, niin sokeasti he olivat vanhastaan tottuneet
tottelemaan tätä päällikköä.

Suonet Kmicicin ohimoilla olivat pullistuneet, silmät kiiluivat


pimeässä kuin kaksi tähteä, semmoinen viha ja kostonhimo niissä
hehkui. Se, mitä hän nyt aikoi tehdä, oli mielettömyyttä, jonka hän
ehkä saisi maksaa hengellään. Mutta koko hänen elämänsä oli ollut
sarja tuommoisia mielettömyyksiä. Polte hänen kupeessaan oli niin
kova, että hän vaistomaisesti tavan takaa vei sille kätensä, mutta
ajatuksissa oli Kuklinowski, ja hän oli valmis odottamaan tätä vaikka
aamuun asti.

— Kuulehan! — sanoi hän. — Kutsuttiko Müller todellakin hänet


luokseen?

— Ei, — vastasi ukko. — Sen keksin minä suoriutuaksemme


helpommin näistä. Viittä vastaan olisi meidän kolmen ollut vaikea
taistella, sillä joku olisi huutanut.

— Se on hyvä! Hän tulee tänne takaisin joko yksin tahi miehiä


mukanaan.
Jos hänen kanssaan on muutama mies, niin hyökätkää heti näiden
kimppuun. Hänet itsensä jättäkää minulle. Sitten kiireesti satulaan!…
Onko teillä kellään pistolia?

— Minulla on! — sanoi Kosma.

— Anna tänne! Onko se ladattu?

— On.

— Hyvä! Jos hän tulee yksin, niin heti hänet nähtyänne hyökätkää
hänen päälleen ja tukkikaa hänen suunsa. Voitte työntää hänen
oman lakkinsa hänen suuhunsa.

— Kuten käskette! — sanoi ukko. — Salliiko teidän armonne, että


tutkimme noiden taskut? Olemme köyhiä miehiä…

Näin sanoen hän osoitti oljilla makaavia ruumiita.

— Ei! Olkaa kaiken aikaa valmiina! Mitä löydätte Kuklinowskilta, se


on teidän!
— Jos hän palaa yksin, — sanoi ukko, — niin en pelkää mitään.
Asetun ovelle, ja tulipa leiristä kuka hyvänsä, niin sanon, että eversti
on kieltänyt päästämästä.

— Hyvä niin! Olkaa nyt varuillanne!

Kuului hevosen kavioitten kopina. Kmicic hypähti pystyyn ja asettui


seinän viereen varjoon. Kosma ja Damian asettuivat oven kahden
puolen kuin kaksi kissaa vaaniessaan hiirtä.

— Yksin! — sanoi ukko hieroen käsiään.

— Yksin! — toistivat Kosma ja Damian. Kavioitten kapse läheni ja


loppui äkkiä. Sensijaan kuului oven takaa ääni:

— Tulkoon joku sieltä pitelemään hevosta! Ukko kiiruhti ulos.

Tuli hetken hiljaisuus, jonka jälkeen riihessä olijat kuulivat


seuraavan keskustelun:

— Sinäkö siinä, Kiemlicz? Mitä helvettiä, oletko sinä tullut


hulluksi?… Müller nukkuu, vahti ei tahtonut päästää minua hänen
luokseen ja sanoi, että mitään ruotsalaista upseeria ei siellä ollut
käynytkään!… Mitä tämä on?

— Se upseeri odottaa teidän armoanne täällä riihessä. Tuli heti


teidän armonne lähdettyä… Sanoo, että hänellä on tärkeätä
puhuttavaa ja odottaa parhaillaan.

— Mitä tämä kaikki merkitsee?… Entä vanki?

— Riippuu.
Ovi narisi, ja Kuklinowski tuli sisälle, mutta samassa kaksi rautaista
kouraa puristi hänen kurkkuaan ja tukahdutti hänen huutonsa.
Kosma ja Damian tottuneesti kuin ammattirosvot ainakin paiskasivat
hänet maahan, painoivat polvillaan hänen rintaansa niin että
kylkiluut rutisivat ja tukkivat silmänräpäyksessä hänen suunsa.

Silloin Kmicic tuli esille, valaisi hänen kasvojaan palavalla sudilla ja


sanoi:

— Ahaa, se on herra Kuklinowski!… Nyt on minulla jotakin


puhuttavaa sinulle!

Kuklinowskin kasvot olivat siniset ja suonet niissä niin pullistuneet


kuin olisivat halkeamaisillaan, mutta hänen pullistuneissa ja
verestävissä silmissään kuvastui ainakin yhtä paljon kummastusta
kuin pelkoa.

— Riisukaa hänet ja ripustakaa orteen! — huusi Kmicic.

Kosma ja Damian alkoivat riisua häntä niin innokkaasti kuin olisivat


tahtoneet vaatteitten kera viedä häneltä nahankin.

Neljännestunnin kuluttua Kuklinowski riippui orressa kädet ja jalat


sidottuina.

Kmicic asettui hänen eteensä kädet puuskassa ja alkoi hirveästi


herjata häntä.

— No, herra Kuklinowski, — sanoi hän, — kumpi on parempi,


Kmicic vai
Kuklinowski?

Sitten hän otti taas käteensä palavan sudin ja astui lähemmäksi.


— Sinun leirisi on nuolen kantaman päässä, tuhat sinun kaltaistasi
konnaa valmiina kuulemaan kutsuasi… Sinun ruotsalainen kenraalisi
on lähellä, mutta sinä riiput samassa orressa, missä aioit minut
kärventää… Tunnetko nyt Kmicicin! Sinä tahdoit olla hänen
veroisensa, tarjouduit hänelle toveriksi… Sinä varas, sinä iljetys,
verikoira, kurja akka! Sinä herra Roistonheimo, sinä epäsikiö, sinä
moukka! Voisin antaa paloitella sinut puukolla kuin kukonpojan,
mutta parempi on paistaa sinut elävältä niinkuin aioit tehdä minulle…

Näin sanottuaan hän asetti sudin onnettoman orressa riippujan


kylkeä vasten ja piti sitä siinä niin kauan, että palaneen lihan käry
levisi riiheen.

Kuklinowski vääntelehti niin että heilui nuorassaan. Hänen


silmänsä, jotka olivat luotuina Kmiciciin, ilmaisivat kauheata kipua ja
pyysivät armoa. Hänen tukitusta suustaan lähti tukahdettuja
valitushuutoja. Mutta sodat olivat kovettaneet Andrzejn sydämen,
niin että se ei tuntenut sääliä, varsinkaan pettureita kohtaan.

Otettuaan sudin pois Kuklinowskin kupeesta hän asetti sen vähäksi


aikaa tämän nenän alle, poltti pois hänen viiksensä, silmäripsensä ja
kulmakarvansa ja sanoi sitten:

— Lahjoitan sinulle henkesi, että voisit vielä muistella Kmiciciä.


Riipu tässä huomiseen ja rukoile Jumalaa, että hän lähettäisi tänne
ihmisiä, ennenkuin palellut kuoliaaksi.

Sitten hän huusi Kosmalle ja Damianille:

— Hevosten selkään!

He lähtivät riihestä.
Puolen tunnin kuluttua levisivät neljän ratsastajan ympärillä tyhjät
ja äänettömät kentät. He hengittivät raikasta ilmaa, jossa ei ollut
ruudin hajua. Kmicic ratsasti edellä, Kiemliczit hänen jäljessään.
Nämä puhelivat hiljaa keskenään, Kmicic rukoili itsekseen
aamurukouksia, sillä kohta alkoi päivä sarastaa.

Väliin pääsi puoleksi tukahdutettu huudahdus hänen huuliltaan,


kun polte kupeessa kävi sietämättömäksi Mutta samalla hän tunsi
olevansa ratsun selässä ja vapaa, ja kun hän ajatteli, että hänen oli
onnistunut räjähdyttää rikki suuri tykki ja pelastua Kuklinowskin
käsistä sekä lisäksi vielä kostaa hänelle, täytti hänen mielensä niin
suuri riemu, että kipu ei hänestä ollut mitään.

Isän ja poikien hiljainen keskustelu oli tällä välin muuttunut


äänekkääksi riidaksi.

— Niin, tässä on kukkaro, — sanoi ukko vihaisesti, — mutta missä


ovat sormukset? Hänellä oli sormuksia sormissa ja yhdessä oli kivi,
joka oli ainakin kahdenkymmenen tshervonetsin arvoinen!

— En muistanut ottaa, — sanoi Kosma.

— Hiisi vieköön! Minä olen vanha, mutta minun on pidettävä huoli


kaikesta, sillä näillä lurjuksilla ei ole hitaistakaan järkeä! Olette
unhottaneet sormukset?… Valehtelette hävyttömästi!

— Menkää katsomaan, jos ette usko, isä! — murahti Damian.

— Valehtelette, lurjukset! Teette vääryyttä vanhalle isällenne!


Semmoisia poikia minulla on! Parempi olisi, että en olisi siittänyt
teitä! Saatte kuolla ilman siunaustani!

Kmicic hiljensi hevosensa vauhtia.


— Kuulkaahan! — sanoi hän. Riita taukosi, Kiemliczit kiiruhtivat
hänen luokseen, ja he jatkoivat matkaa yhdessä joukossa.

— Tunnetteko tien Sleesian rajalle? — kysyi Andrzej.

— Tokihan, Jumalan äidin nimessä, kyllä tunnemme! — vastasi


ukko.

— Eikä tiellä ole ruotsalaista sotaväkeä?

— Ei, ne ovat kaikki Częstochowon luona… Jonkun yksityisen


ruotsalaisen saattaa tavata, mutta sehän ei ole haitaksi.

Seurasi jonkin aikaa kestävä äänettömyys.

— Te olette siis olleet Kuklinowskin palveluksessa, — kysyi sitten


Kmicic.

— Niin… kyllä! Ajattelimme, että pysyttelemällä täällä


läheisyydessä voimme palvella pyhää veljeskuntaa ja teidän
armoanne. Mutta me emme ole taistelleet luostaria vastaan, Jumala
meitä semmoisesta varjelkoon! Emme ole nauttineet mitään
palkkaakaan, sen vain, mitä meidän on onnistunut löytää
ruotsalaisten taskuista.

— Kuinka? Ruotsalaistenko?

— Niin, me tahdoimme vaikkapa muurien ulkopuolella palvella


Pyhää Neitsyttä. Siksi liikuskelimme öisin leirin ympärillä ja joskus
päivälläkin, kun niin sattui, ja kun joku ruotsalainen sattui olemaan
erillään toisista, niin me… tuota noin… me hänet…

— Pehmitimme! — lopettivat lauseen Kosma ja Damian.


Kmicic naurahti.

— Saipa Kuklinowski teistä hyvät palvelijat! — sanoi hän. —


Tiesikö hän siitä?

— Asetettiin tutkimuskomiteoita, toimitettiin kuulusteluja… Hän


tiesi asian ja vaati, senkin roisto, meiltä taalerin jokaisesta päästä…
Uhkasi muussa tapauksessa antaa meidät ilmi… Senkin rosvo, nylki
köyhiä ihmisiä… Siksipä me olimmekin uskollisia teidän armollenne,
sillä teidän armonne on toista maata… Teidän armonne antaa vielä
omistaankin, mutta hän otti taalerin joka päästä, hyötyi meidän
työstämme, meidän vaivannäöstämme… Hiisi hänet vieköön!

— Minä palkitsen teitä runsaasti siitä, mitä olette tehneet! — sanoi


Kmicic. — En odottanut semmoista teiltä.

Kaukainen tykin jyrinä keskeytti hänen puheensa. Nähtävästi


ruotsalaiset alkoivat taas ampua aamun sarastaessa. Kohta jyrinä tuli
kovemmaksi. Kmicic pysähdytti hevosensa. Hän luuli erottavansa
luostarin tykkien äänen ruotsalaisten tykeistä. Heristellen uhkaavasti
nyrkkiään siihen suuntaan, missä vihollisen leiri oli, hän sanoi:

— Ampukaa, ampukaa! Missä on suurin tykkinne?


KAHDEKSASTOISTA LUKU.

Jättiläistykin menetys teki Mülleriin todellakin musertavan


vaikutuksen, koska hänen kaikki toiveensa juuri perustuivat tuohon
tykkiin. Jalkaväki oli jo valmis väkirynnäkköön, portaat ja risukimput
olivat jo varatut, mutta nyt täytyi luopua koko väkirynnäköstä.

Yritys räjähdyttää luostari ilmaan maanalaisten ruutihautojen


avulla epäonnistui kokonaan. Tottuneet kaivantojen laittajat, joita oli
tuotu Olkuszista, kohtasivat luostaria lähestyessään kovan kallion ja
joutuivat kaikista varokeinoista huolimatta luostarin tarkan tykkitulen
uhreiksi. Mieliala sotajoukossa lamautui päivä päivältä yhä enemmän
ja yhä vakuutetumpia oltiin siitä, että luostaria oli mahdoton
valloittaa.

Viimein alkoi itse Müllerkin olla yhä vähemmän toivehikas, ja


kolubriinin menettäminen saattoi hänet aivan epätoivoon. Hänet
valtasi täydellisen voimattomuuden tunne. Seuraavana päivänä
pidettiin sotaneuvottelu. Müllerin tarkoituksena oli vain antaa
upseereille tilaisuus kehoittaa häntä luopumaan koko piirityksestä.

Kokoonnuttiin synkkinä ja alakuloisina. Ei kenenkään silmistä


näkynyt toivoa eikä taisteluintoa. Äänettöminä istuuduttiin pöydän
ympärille suuressa, kylmässä huoneessa, jossa hengitys muuttui
höyryksi, ja kasvot sen sisällä olivat kuin sumussa. Puolalaiset
päälliköt olivat poissa kokouksesta. Ei kukaan puhunut, sillä ei
kukaan tahtonut ensimmäisenä esittää sitä, mikä kuitenkin oli ainoa
mahdollisuus. Kaikki odottivat, mitä Müller sanoisi. Tämä antoi tuoda
pöytään lämmitettyä viiniä toivoen siten saavansa puheen
luistamaan.

Puhe alkoikin kohta luistaa. Ei kukaan vieläkään tahtonut


ensimmäisenä ehdottaa piirityksestä luopumista, mutta sen sijaan
tuotiin esille kaikki kauna ja katkeruus, joka täytti mielet. Äkäisiä
syytöksiä tehtiin Wrzeszczowiczia vastaan, ja Hessenin prinssi pisteli
väliin kärkeviä huomautuksiaan. Sadowski lausui haikailematta
ajatuksensa Wrzeszczowiczin uusimmasta suunnitelmasta, joka oli
se, että oli levitettävä huhu, että kaivantojen laittajat olivat löytäneet
maanalaisen käytävän, joka johti kirkon alle.

— Kun tämä huhu leviää, — sanoi Wrzeszczowicz, — niin


puolalaisetkin rukoilevat munkkeja antautumaan, jotta tämä
taikauskon tyyssija säilyisi paikallaan.

— Jumaliste, tuohan on tarkalleen kuin juttu Troijan piirityksestä,


mutta hän luulee keksineensä jotakin vallan uutta! — sanoi
Sadowski.

Mutta Mülleriä tämä tuuma miellytti. Hän tiesi, että luostarissa oli
eräs, tosin heikko, puolue, joka halusi antautumista, ja saattoihan
pelko levitä varusväen keskuuteen ja vallata nekin, jotka tähän
saakka olivat halunneet taistella viimeiseen asti.

— Koettakaamme, koettakaamme! — sanoi Müller. —


Suostuneekohan Kaliński tahi Zbrozek vielä menemään lähettiläänä
luostariin, ja uskonevatko he tuon käytävän olemassaoloa?

— Joka tapauksessa Kuklinowski suostuu, — vastasi


Wrzeszczowicz. —
Mutta parempi olisi, että hän itsekin uskoisi käytävän olevan
olemassa.

Samassa kuului ulkoa kavioitten kapsetta.

— Jopa saapui myös herra Zbrozek! — sanoi Hessenin prinssi


katsoen ulos ikkunasta.

Kohta sen jälkeen kuului eteisestä kannusten kilinää, ja Zbrozek


astui, tahi paremminkin syöksyi, huoneeseen. Hänen kasvonsa olivat
kalpeat ja kiihtyneet, ja ennenkuin upseerit ennättivät kysyä syytä
hänen mielenliikutukseensa hän huudahti:

— Kuklinowski on kuollut!

— Mitä? Mitä te sanotte? Mitä on tapahtunut? — kysyi Müller.

— Sallikaa minun hiukan hengähtää! — sanoi Zbrozek. — Sitä,


minkä minä olen nähnyt, ei kukaan voi kuvitellakaan.

— Sanokaa pian! Onko hänet murhattu? — huusivat kaikki.

— Kmicic! — vastasi Zbrozek.

Upseerit hyppäsivät kaikki paikoiltaan ja katselivat Zbrozekia kuin


tämä olisi menettänyt järkensä. Hän puhui läähättäen:

— Jos en olisi nähnyt omin silmin, niin en uskoisi, sillä se on aivan


yliluonnollista. Kuklinowski on vainaja, kolme sotamiestä tapettu,
Kmicic kadonnut jäljettömiin. Tiesin, että hän on pelättävä mies.
Hänen maineensa tunnetaan koko maassa… Mutta tämmöistä ei ole
ihminen voinut tehdä, sen on tehnyt piru… Hän on vapautunut
siteistään, tappanut sotamiehet ja kiduttanut Kuklinowskin
kuoliaaksi.

— Se on mahdotonta! Sitä ei voi uskoa! — kuiskasi Sadowski.

— Tuo Kmicic näytti, mihin hän pystyy! — sanoi Hessenin prinssi.


— Me emme uskoneet eilen puolalaisia, kun he meille puhuivat, mikä
hän on miehiään. Luulimme heidän liioittelevan tapansa mukaan.

— Täällä tulee hulluksi! — huudahti Wrzeszczowicz.

Müller piteli käsillään päätään eikä puhunut mitään. Kun hän


viimein nosti silmänsä, säkenöi niistä vihastusta ja epäluuloa.

— Herra Zbrozek! — sanoi hän. — Vaikka se olisi ollut pirukin eikä


ihminen, niin ei hän olisi voinut suorittaa sitä ilman jonkun apua ja
petosta. Kmicicillä oli täällä ihailijansa ja Kuklinowskilla
vihamiehensä, ja te kuuluitte niiden joukkoon!

Zbrozek oli tuittupäinen soturi. Kuultuaan syytöksen, joka


kohdistui häneen, hän tuli vielä kalpeammaksi, nousi paikaltaan,
meni Müllerin eteen ja katsoi häntä suoraan silmiin.

— Epäileekö teidän ylhäisyytenne minua? — kysyi hän.

Syntyi perin kiusallinen äänettömyys. Kaikki läsnäolijat olivat


varmat siitä, että jos Müller vastaa myöntävästi, niin tapahtuu
jotakin kauheata ja sotahistoriassa ennen esiintymätöntä. Jokainen
tarttui miekan kahvaan. Sadowski veti miekkansa tupesta.
Mutta samassa upseerit näkivät ikkunasta, että piha oli täynnä
puolalaisia ratsumiehiä. Luultavasti nekin olivat tulleet tuomaan
tietoa Kuklinowskin kuolemasta. Jos nyt olisi syntynyt kahakka,
olisivat ne aivan varmasti asettuneet Zbrozekin puolelle. Müllerkin
näki ne, ja vaikka hän oli kalpea kiukusta, niin hän kuitenkin hillitsi
itsensä eikä ollut huomaavinaan, että Zbrozekin esiintymisessä oli
uhmailua, vaan sanoi äänellä, jonka hän koetti saada kuulumaan
luonnolliselta:

— Kertokaa meille asia yksityiskohtaisesti! Zbrozek seisoi vielä


jonkin aikaa laajentunein sieraimin, mutta hänkin hillitsi mielensä, ja
sitäpaitsi hänen ajatuksensa kääntyivät toisaalle, kun äsken
saapuneet toverit myös tulivat sisälle.

— Kuklinowski on murhattu! — sanoivat he töinen toisensa


jälkeen.

— Kuklinowski on tapettu!

— Hänen joukkonsa on hajoamassa! Sotamiehet ovat hulluina!

— Antakaa herra Zbrozekin puhua, koska hän ensimmäisenä toi


uutisen! — huusi Müller.

Vähitellen melu asettui, ja Zbrozek alkoi puhua:

— Herroille on tunnettua, että viime neuvottelussa vaadin


Kuklinowskin kaksintaisteluun. Olin Kmicicin ihailija, se on totta,
mutta täytyyhän teidänkin, jotka olette hänen vihollisiaan, myöntää,
ettei kuka tahansa kykene suorittamaan sellaista tekoa kuin tuo tykin
räjähdyttäminen oli. Miehuutta on kunnioitettava vihollisessakin, ja
siksi ojensin hänelle käteni, mutta hän ei antanut minulle omaansa,
vaan nimitti minua petturiksi. Senvuoksi ajattelin: tehköön
Kuklinowski hänelle mitä tahtoo… Tahdoin vain sitä, että jos
Kuklinowski menettelisi vastoin ritarillisuuden vaatimuksia, niin
tuosta teosta ei häpeä lankeaisi kaikkien puolalaisten ja niiden
joukossa minunkin päälle. Senvuoksi tahdoin joka tapauksessa
taistella Kuklinowskin kanssa, ja varhain tänä aamuna minä kahden
toverini kanssa lähdin Kuklinowskin leiriin. Hän ei ollut siellä.
Sanottiin, että hän ei ollut palannut koko yönä, mutta ei oltu
levottomia, koska luultiin hänen jääneen teidän ylhäisyytenne luokse.
Eräältä sotamieheltä sain sitten tietää, että hän oli yöllä vienyt
Kmicicin erääseen riiheen, jossa aikoi hänet paistaa elävänä. Menen
riihen luo, ovet ovat auki. Astun sisälle ja näen alastoman ruumiin
riippuvan orressa… Ajattelin, että se oli Kmicic, mutta kun silmäni
tottuivat pimeään, huomasin, että ruumis oli laiha ja luiseva, kun
taas Kmicic oli kuin Herkules… Ihmettelin, miten hän oli voinut niin
kutistua yhdessä yössä… Menin lähemmäksi — se oli Kuklinowski!

— Orressa? — kysyi Müller.

— Niin! Tein ristinmerkin, sillä luulin, että tämä oli lumousta. Vasta
kun näin kolmen sotamiehen ruumiit, valkeni minulle asian oikea
laita. Tuo hirveä mies oli ne tappanut, ripustanut tämän orteen,
kärventänyt pahasti ja sitten poistunut.

— Sleesian raja on lähellä! — sanoi Sadowski.

Syntyi äänettömyys.

Kaikki epäluulo Zbrozekia kohtaan katosi Müllerin mielestä. Mutta


itse tapaus saattoi hänet ymmälle ja synnytti hänessä epämääräistä
levottomuutta. Hän näki ympärilleen kasaantuneina vaaroja, tahi
oikeastaan niiden uhkaavia varjoja, eikä tietänyt, kuinka niitä
vastaan oli taisteltava. Hän tunsi, että häntä ympäröi jonkinmoinen
vastoinkäymisten ketju. Sen ensimmäiset renkaat olivat hänen
silmiensä edessä, mutta seuraavat tulevaisuuden pimeän peitossa.
Hänet valtasi semmoinen tunne, kuin hän olisi luhistumaisillaan
olevassa talossa, joka saattoi millä hetkellä hyvänsä sortua hänen
päälleen.

Wrzeszczowicz löi äkkiä otsaansa.

— Kautta Jumalan! — sanoi hän. — Kun eilen näin Kmicicin, tuntui


minusta, että olin hänet jossakin tavannut. Olen varmasti ollut
jossakin hänen kanssaan tekemisissä, mutta missä?… missä?

Hän alkoi hieroa otsaansa.

— Mitä se meitä auttaa? — sanoi Müller. — Jos muistattekin, herra


kreivi, niin ette sillä laita tykkiä eheäksi ettekä herätä kuolleista
Kuklinowskia!

Sen jälkeen hän kääntyi upseerien puoleen:

— Kutka teistä, hyvät herrat, haluavat lähteä kanssani


tapahtumapaikalle?

Kaikki olivat valmiit lähtemään, sillä jokainen oli utelias.

Hevoset tuotiin esille ja lähdettiin matkaan kenraali etunenässä.


Kun he lähestyivät riihtä, näkivät he kymmenkunta puolalaista
ratsumiestä rakennuksen luona tiellä ja kedolla.

— Mitä väkeä nuo ovat? — kysyi Müller Zbrozekilta.


— Varmaankin Kuklinowskin miehiä. Zbrozek alkoi viitata yhtä
ratsastajista luokseen:

— Tule tänne! Joudu! Sotamies tuli luo.

— Oletteko Kuklinowskin joukosta?

— Kyllä.

— Missä on muu osa rykmenttiä?

— Ovat menneet tiehensä. Sanoivat, että eivät tahdo enää sotia


Jasna
Góraa vastaan.

— Mitä hän sanoo? — kysyi Müller. Zbrozek käänsi kenraalille


sotamiehen sanat.

— Kysykää häneltä, minne ne ovat menneet, — sanoi kenraali.

Zbrozek toisti kysymyksen.

— Ei sitä kukaan tiedä,-vastasi sotamies. Muutamat menivät


Sleesiaan. Toiset sanoivat tahtovansa palvella Kmiciciä, sillä toista
semmoista päällikköä ei ole puolalaisten eikä ruotsalaisten joukossa.

Kun Zbrozek käänsi Müllerille nämäkin sotamiehen sanat, vaipui


kenraali ajatuksiinsa. Sellaiset miehet kuin Kuklinowskin olivat
todellakin valmiit empimättä siirtymään Kmicicin johtoon. Mutta
silloin he saattoivat olla uhkana, jollei juuri Müllerin armeijalle, niin
ainakin kuormastolle ja kulkuyhteydelle.

Vaarat kasaantuivat yhä.


Samaan suuntaan lienee ajatellut myös Zbrozek, sillä hän sanoi
aivan kuin vastaukseksi noihin Müllerin ajatuksiin:

— Varmaa on, että myrsky on nousemassa koko valtakunnassa.


Kun tuommoinen Kmicic vain huudahtaa, niin sadat ja tuhannet
kerääntyvät hänen ympärilleen, varsinkin sen jälkeen, mitä hän nyt
on tehnyt.

— Ja mitä hän voittaa? — kysyi Müller.

— Teidän ylhäisyytenne muistanee, että tämä mies saattoi


Chowańskin epätoivoon, ja Chowańskilla oli kuusi kertaa niin paljon
miehiä kuin meillä. Ei yksikään kuorma tule meille, jos hän niin
tahtoo, ja koska kaikki maatilat on ryöstetty, voi leirissä syntyä
nälänhätä.

— Luotatteko sotamiehiinne?

— Enemmän kuin itseeni! — sanoi Zbrozek rohkeasti ja


avomielisesti.

— Kuinka? Enemmän kuin itseenne?

— Niin, sillä totta puhuen olemme saaneet tarpeeksemme tästä


piirityksestä.

— Olen varma siitä, että se pian loppuu.

— Kysymys on vain: miten? Muuten linnoituksen valloittaminen


olisi nyt yhtä suuri onnettomuus meille kuin piirityksestä luopuminen.

He olivat saapuneet riihen luo. Müller astui alas hevosen selästä,


toiset upseerit tekivät samoin, ja kaikki menivät sisälle. Sotamiehet
olivat jo ottaneet Kuklinowskin alas, asettaneet oljille ja peittäneet
loimella. Kolmen sotamiehen ruumiit olivat hänen vieressään.

— Ne on surmattu puukoilla, — kuiskasi Zbrozek.

— Entä Kuklinowski?

— Kuklinowskissa ei ole muita haavoja kuin palohaava kupeessa.


Hän on joko paleltunut kuoliaaksi tahi tukehtunut, sillä hänellä on
oma hattunsa suussaan.

— Nostakaa peite!

Sotamies nosti loimen kulmaa. Näkyviin tulivat kauheat, siniset ja


pöhöttyneet kasvot silmät pullollaan. Jäljellejääneet yksityiset
viiksien karvat törröttivät kankeina ja hengityksestä huurteisina.
Kasvot olivat niin kamalan näköiset, että Müller, vaikka olikin tottunut
näkemään monenlaisia kauhuja, peräytyi ja huusi:

— Peittäkää hänet! Tämähän on kauheata! Synkkä äänettömyys


vallitsi riihessä.

— Miksi me tänne tulimme? — kysyi Hessenin prinssi sylkäisten. —


Nyt ei käy syönti koko päivänä.

Äkkiä Müller sai jonkinmoisen raivokohtauksen, joka lähenteli


mielenvikaisuutta. Hänen kasvonsa tulivat sinisiksi, silmät
mulkoilivat, ja hän kiristeli hampaitaan. Villi verenhimo valtasi hänet,
ja hän tahtoi välttämättömästi kostaa jollekulle. Kääntyen Zbrozekin
puoleen hän huudahti:

— Missä on se sotamies, joka tiesi Kuklinowskin olevan riihessä?


Tuokaa hänet tänne! Hän on varmaankin osallinen rikokseen!
— En tiedä, onko se sotamies enää täällä! — vastasi Zbrozek. —
Kaikki
Kuklinowskin miehet ovat menneet tiehensä.

— Ottakaa hänet sitten kiinni! — huusi Müller raivoissaan.

— Ottakaa itse! — huusi Zbrozek niinikään raivostuen.

Taaskin riippui aivan kuin hiuskarvasta, puhkeaisivatko


ruotsalaisten ja puolalaisten kireät välit kahakaksi. Puolalaiset
painautuivat lähemmäksi Zbrozekia ja kalisuttivat sapeleitaan.

Samassa kuului ulkoa melua, laukauksia ja kavioitten kapsetta.


Riiheen syöksähti ruotsalainen ratsuväen upseeri.

— Kenraali! — huusi hän. — Luostarista on tehty hyökkäys ulos!


Ruutihautaa laittavat louhijat on hakattu maahan! Yksi
ratsuväkiosasto on ajettu pakoon!

— Minä tulen hulluksi! — huusi Müller repien tekotukkaansa. —


Ratsujen selkään!

Hurjaa vauhtia lähdettiin heti luostaria kohti, niin että lumi sinkoili
kavioista. Sata Sadowskin ratsumiestä yhtyi joukkoon ollakseen
Müllerin apuna. Tiellä he näkivät hajoitetun ratsuväkiosaston miehiä
epäjärjestyksessä pakenemassa. Niin olivat jo tähän saakka
verrattomat ruotsalaiset sotilaat menettäneet miehuutensa! Olipa
patteritkin jätetty oman onnensa nojaan, vaikka niitä ei uhannut
mikään vaara. Muutamia pakolaisia pistivät upseerit ja ratsumiehet
kuoliaiksi.

Kenraali joukkoineen saapui linnoituksen luo parahiksi nähdäkseen


hyökkääjien palaavan onnellisesti takaisin luostariin. Heidän laulunsa,
riemuhuutonsa ja naurunsa kuuluivat selvästi Müllerin korviin.
Vieläpä jotkut yksityiset sotamiehet heristelivät verisiä sapeleitaan
esikunnalle. Ruotsalaisen kenraalin vieressä olevat puolalaiset
tunsivat Zamoyskin, joka oli hyökkäysjoukon johtajana ja nyt
nähtyään esikunnan pysähtyi ja kumarsi sille kohteliaasti. Eipä
kumma! Hän tunsi olevansa jo luostarin tykkien turvissa.

Pattereilta kohosi savua, ja viheltäen lensi kuulia upseerien


joukkoon.
Muutamat ratsumiehet pitelivät kupeitaan, ja vaikerrusta kuului.

— Olemme ampumalinjalla!… Takaisin! — komensi Sadowski.

Zbrozek tarttui Müllerin hevosen suitsiin.

— Kenraali, takaisin! Henki on kysymyksessä! Müller oli kuin


jähmettynyt, ei puhunut mitään ja antoi johtaa itsensä pois
kuulasateesta. Tultuaan päämajaansa hän lukitsi huoneensa eikä
ottanut koko päivänä ketään vastaan.

Silloin Wrzeszczowicz otti johdon käsiinsä ja alkoi erittäin


tarmokkaasti valmistella väkirynnäkköä. Uusia valleja luotiin,
sotamiehet olivat kallionlouhijain apuna ruutihautoja laittamassa.
Kuumeinen toiminta vallitsi koko leirissä, uusi henki näytti syntyneen
piirittäjiin.

Muutamia päiviä myöhemmin levisi ruotsalaisten leirissä ja


erikoisesti puolalaisten keskuudessa huhu, että louhijat olivat
löytäneet maanalaisen käytävän, joka johti aivan kirkon alle ja että
riippui vain kenraalin omasta tahdosta, räjähdyttäisikö hän koko
luostarin ilmaan.
Rajaton riemu valtasi pakkasen, nälän ja tuloksettoman työn
näännyttämät sotamiehet.

Wrzeszczowicz oli läsnä kaikkialla, innostutti sotamiehiä, vahvisti


sata kertaa päivässä todeksi uutisen maanalaisen käytävän
löytymisestä ja pani toimeen kekkereitä.

Tuon riemun kaiku kuului lopulta luostariin asti. Salaman


nopeudella levisi muureilla tieto, että miinoja oli jo valmiina luostarin
räjähdyttämistä varten. Rohkeimmatkin masentuivat. Naiset
ympäröivät itkien priorin asunnon, ojensivat hänen näyttäytyessään
lapsia häntä kohti ja huusivat:

— Älä tuhoa viattomia!… Niiden veri tulee sinun päällesi!

Tuo sankari munkin viitassa sai elää raskaampia ja katkerampia


päiviä kuin koskaan ennen. Onneksi ruotsalaiset eivät ryhtyneet
väkirynnäkköön, koska sillä juuri tahtoivat osoittaa piiritetyille, että
eivät enää tarvitse kuulia eivätkä muita aseita, kun he kerran voivat
saavuttaa tarkoituksen sytyttämällä vain sytytyslangan. Mutta siksipä
pelko luostarissa yhä kasvoi, öisin olivat jotkut kuulevinaan ääntä
maan alta ja arvelivat ruotsalaisten siellä liikuskelevan. Suuri osa
veljeskuntaakin menetti rohkeutensa ja saapui isä Stradowskin
johdolla taivuttamaan prioria ryhtymään neuvotteluihin vihollisen
kanssa antautumisesta. Suuri osa aatelia ja sotilaita kannatti heitä.
Isä Kordecki kehoitti pitkässä ja innokkaassa puheessa munkkeja ja
aatelisia säilyttämään mielenmalttinsa. Puhe vaikuttikin. Taas palasi
sydämiin toivo, ja munkit palasivat kirkkoon, sotamiehet muureille.

Lounaisella portilla törähti torvi. Kaikki kiiruhtivat katsomaan, mitä


oli tekeillä.
Ruotsalainen sanansaattaja, toi kirjeen.

Munkit kokoontuivat neuvottelusaliin. Kirje oli Wrzeszczowiczilta, ja


siinä ilmoitettiin, että jos linnoitus ei antaudu huomiseen mennessä,
niin se räjähdytetään ilmaan.

Mutta luostarissa-olijain mielet olivat rohkeat. Olipa jo alettu


epäillä koko räjähdyttämisen mahdollisuuttakin.

— Tyhjää peloitusta! — huusivat priori ja aateliset.

— Jos niin on, niin kirjoittakaamme heille, että eivät suotta meitä
säälisi, vaan räjähdyttäisivät!

Ja niin todella kirjoitettiinkin.

Samaan aikaan sotamiehet, jotka olivat kokoontuneet kirjeen


tuojan ympärille, naureskelivat tämän peloitteluille.

— Hyvä on! — sanoivat he. — Turhaa teidän onkin meitä säästää.


Pikemmin vain menemme taivaaseen!

Se taas, joka antoi lähetille vastauskirjelmän, sanoi tälle:

— Älkää kuluttako turhaan sanoja ja aikaa!… Ahdistaahan teitä


puutekin, kun taas meillä, Jumalan kiitos, ei ole mitään hätää.

Näin meni myttyyn Wrzeszczowiczin viimeinenkin juoni. Kun vielä


päivä oli kulunut, havaittiin, miten perusteettomia uhkailut olivat
olleet, ja rauha palasi luostariin.

Joulu lähestyi. Vanha kerjäläisvaimo toi Müllerille isä Kordeckilta


kirjeen, jossa pyydettiin aselepoa. Vahdit ja upseerit nauroivat ja
pilkkasivat näin harvinaista lähettilästä, mutta kerjäläisvaimo vastasi:
— Kukaan muu ei tahtonut lähteä, koska te kohtelette lähettiläitä
kuin rosvot, mutta minä läksin leipäpalan tähden. Minulla ei ole enää
pitkä aika elettävänä maan päällä, ja teitä minä en pelkää. Jos ette
sitä usko, niin olenhan vallassanne.

Mutta hänelle ei tehty mitään pahaa, vieläpä Müller, tahtoen taas


koettaa myönnytysten vaikutusta, suostui priorin pyyntöön.

Tuli joulun aatto. Hämärän tultua valaistiin koko luostari


joulukynttilöillä. Oli tyyni ja kaunis, mutta kylmä ilta. Ruotsalaiset
sotamiehet, jotka kylmästä kohmettuneina seisoivat valleilla,
katselivat kaukaa luostarin tummille muureille, ja heidän mieleensä
muistuivat lämpimät majat kotimaassa, vaimo, lapset ja kynttilöin
koristetut kuuset, ja monesta rautaan puetusta rinnasta kohosi
kaipauksen, murheen ja epätoivon huokaus.

Mutta luostarissa istuivat piiritetyt oljilla peitettyjen pöytien


ääressä ja mursivat joululeipää. Ilo ja rauha säteili kaikkien
kasvoista, sillä jokainen aavisti, olipa melkein varmakin, että
koettelemusten aika pian on ohi.

— Huomenna taas aloitetaan pommitus, mutta se on viimeinen


kerta, — sanoivat munkit ja sotilaat. — Kenet Jumala on määrännyt
kaatumaan, hän olkoon kiitollinen, sillä joka jouluna kuolee uskon
puolesta, sille ovat taivaan portit avoinna, ja hän tulee autuaaksi.

He toivottivat toisilleen menestystä, pitkää ikää tahi taivaallista


kruunua, ja sellainen rauha täytti kaikki sydämet, kuin kaikki vaara jo
olisi ohi.

Priorin vieressä oli yksi tuoli tyhjänä. Pöydällä tämän tuolin


kohdalla oli nippu joululeipää, joka oli sidottu taivaansinisellä
nauhalla.

Kun kaikki olivat istuutuneet pöytään, mutta kukaan ei käynyt


tuolle tyhjälle paikalle, sanoi Zamoyski:

— Ketä varten, kunnioitettu isä, on tuo paikka?

— Ei ketään varten, — vastasi priori, — vaan sen nuoren miehen


muistoksi, jota kaikki rakastivat kuin omaa poikaansa ja jonka sielu
nyt katsoo meitä iloiten siitä, että olemme säilyttäneet hänet
kiitollisessa muistossa.

— Totisesti! — sanoi Zamoyski. — Hänellä on nyt parempi olo kuin


meillä. Olemme hänelle kiitollisuuden velassa.

Kyynelet nousivat isä Kordeckin silmiin. Czarniecki sanoi:

— Vähäisempiäkin urotöitä kuin hänen mainitaan aikakirjoissa. Jos


Jumala antaa minun elää kauan ja joku minulta kysyy, kuka oli
vanhan ajan sankarien veroinen soturi, niin vastaan: Babinicz.

— Hänen nimensä ei ollut Babinicz, — sanoi priori Kordecki.

— Kuinka? Eikö ollut Babinicz?

— Olen jo kauan tietänyt hänen nimensä, mutta rippisalaisuutena.


Mutta kun hän lähti vaaralliselle retkelleen, sanoi hän minulle: »Jos
kuolen, niin saakoot tietää, kuka olen, jotta oikea maine jäisi
nimelleni ja vanhat syntini olisivat pois pyyhityt.» Hän lähti ja jäi sille
tielleen, ja siksi voin nyt ilmoittaa teille: hän oli Kmicic!

— Tuo kuuluisa Kmicic Liettuasta! — huudahti Czarniecki tarttuen


päähänsä.
— Niin! Sillä tavoin Jumalan armo muuttaa sydämet!

— Ah, nyt ymmärrän, kuinka hän saattoi ottaa suorittaakseen tuon


tehtävän. Nyt ymmärrän, mistä johtui tuo rohkeus ja miehuus, jonka
veroista ei ollut muissa! Kmicic, Kmicic! Tuo peloittava Kmicic, josta
koko Liettua kertoo!

— Tämän jälkeen hänestä ei kerro vain Liettua, vaan koko Puola!

— Hän meitä ensimmäisenä varoitti Wrzeszczowiczista!

— Hänen neuvostaan suljimme ajoissa porttimme ja ryhdyimme


valmistuksiin!

— Hän ampui ensimmäisen ruotsalaisen jousellaan!

— Ja miten monta tykkiä hän heiltä turmelikaan! Entä kuka


surmasi de
Fossin?

— Entä se iso tykki! Kenen ansio on, että emme pelkää huomista
pommitusta?

— Muistelkoon jokainen kunnioittaen häntä ja ylistäköön kaikkialla


hänen nimeään, jotta oikeus tapahtuisi! — sanoi priori Kordecki. —
Suokoon Jumala hänelle iankaikkisen rauhan!

— Ja ikuinen valo loistakoon hänen ylitseen! — vastasivat kaikki


yhteen ääneen.

Mutta Czarniecki ei voinut rauhoittua, vaan hänen ajatuksensa


palasivat yhä Kmiciciin.
— Vaikka hän oli vain tavallisena sotamiehenä, — sanoi hän, —
niin hänessä oli jotakin, joka vaikutti, että johto heti siirtyi hänelle.
Minua ihmetytti usein, että miehet vapaaehtoisesti tottelivat
tuollaista poikaa. Totta puhuen hän oli päällikkö minun patterillani, ja
minä itse tottelin häntä. Kunpa edes olisin tietänyt, että se oli Kmicic!

— Ihmetyttää minua kuitenkin, — sanoi Zamoyski, — että


ruotsalaiset eivät ole ylpeillen ilmoittaneet hänen kuolemastaan.

Isä Kordecki huokasi:

— Hän lienee lentänyt ilmaan yhdessä tykin kanssa.

— Antaisin hakata käden itseltäni, jos se palauttaisi hänet henkiin!


— huudahti Czarniecki. — Että tuommoinen mies kuin Kmicic on
antanut räjähdyttää itsensä ruudilla!

— Hän antoi henkensä puolestamme! — huokasi isä Kordecki.

— Varmaa on, — sanoi Zamoyski, — että jos tuo kolubriini vielä


olisi paikallaan patterilla, niin en näin iloisin mielin ajattelisi
huomispäivää.

— Huomenna Jumala antaa meille uuden voiton! — sanoi isä


Kordecki. —
Noakin arkki ei voi hukkua vedenpaisumukseen.

Näin he puhelivat, ja sitten palasivat taas munkit kirkkoon ja


sotamiehet vartioimaan muureja ja portteja. Suurta valppautta ei
kuitenkaan tarvittu. Myöskin ruotsalaisten leirissä vallitsi tyyni rauha,
sillä heilläkin oli juhlista jaloin.
Oli ihmeen kaunis yö. Tähdet tuikkivat taivaalla vuoroin
punertavina, vuoroin sinisinä. Kuun viheriä hohde valaisi lumikenttiä
linnoituksen ja vihollisen leirin välillä. Oli niin tyyntä, että semmoista
ei ollut koko piirityksen aikana ollut.

Keskiyön aikana ruotsalaiset sotamiehet kuulivat hiljaista urkujen


hyminää, sitten yhtyivät siihen ihmisäänet, lopulta kaikki kirkon
kellot. Iloa, lohdutusta ja suurta rauhaa henki näistä sävelistä, mutta
ruotsalaisten sydämiä alkoi ahdistaa yhä suurempi alakuloisuus ja
epäilys.

Zbrozekin ja Kalińskin sotamiehet menivät lupaa pyytämättä aivan


luostarin muurien luokse. Heitä ei päästetty sisälle, koska pelättiin
salajuonia, mutta heidän sallittiin olla muurien luona. Jotkut heistä
polvistuivat lumeen, toiset nyökkäilivät surullisesti ja huokailivat tahi
löivät rintoihinsa luvaten parannusta. Kaikki kuuntelivat hartaasti ja
kyynelsilmin soittoa ja laulua.

Seuraavana päivänä puolenpäivän aikaan tukahdutti taas tykkien


jyske kaikki muut äänet. Kaikki patterit savusivat, maa tärisi, kirkon
katolle lensi kuten ennenkin pommeja, kuulia ja kranaatteja, putkiin
kiinnitettyjä tulisoihtuja, joista tippui sulavaa tinaa, ja putkettomia
tulisoihtuja, rautakappaleita ja palavia tappuroita. Ei koskaan vielä
oltu ammuttu noin taukoamatta, ei koskaan ollut semmoinen rauta-
ja tuliaalto pyyhkeillyt luostaria. Mutta ruotsalaisten tykkien joukosta
puuttui tuo kolubriini, joka yksinään kykeni tuottamaan niin suuria
vaurioita, että väkirynnäkkö olisi ollut mahdollinen.

Muuten piiritetyt jo olivat niin tottuneet tähän kaikkeen, että


jokainen tarkoin tiesi tehtävänsä ja puolustus sujui ilman
komennuksia. laukauksiin vastattiin laukauksilla, jotka yleensä olivat
vielä paremmin tähdättyjä.
Illemmalla lähti Müller katsomaan auringon viimeisten säteitten
valossa pommituksen tuloksia, ja hänen katseensa sattui kirkon
torniin, joka seisoi rauhallisena, taustanaan sininen taivas.

— Tämä luostari seisoo iankaikkisesta iankaikkiseen! — huudahti


hän kiivaasti.

— Amen! — sanoi Zbrozek tyynesti.

Illalla kokoontuivat upseerit kenraalin päämajaan neuvotteluun


tavallista synkempinä. Müller aloitti keskustelun.

— Tämänpäiväinen pommitus, — sanoi hän, — ei ole tuottanut


mitään tuloksia. Ruutimme alkaa loppua, miehistö on sulanut
puoleen alkuperäisestä, ja jäljelläolevatkin ovat haluttomia eivätkä
usko voittoon. Ruokavarastoja meillä ei ole, emmekä voi toivoa
saavamme apujoukkoja.

— Ja luostari seisoo yhtä vakavasti paikallaan kuin ensimmäisenä


piirityspäivänä! - lisäsi Sadowski.

— Mitä meille jää? — Häpeä…

— Olen saanut käskyn, — sanoi kenraali, — että joko selvittäisin


nopeasti loppuun tämän asian tahi vetäytyisin pois ja menisin
Preussiin.

— Mitä jää tehtäväksemme? — toisti Hessenin prinssi.

Kaikkien katseet kääntyivät Wrzeszczowicziin. Tämä sanoi:

— Pelastaa kunnia!
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

textbookfull.com

You might also like