0% found this document useful (0 votes)
17 views60 pages

Learning Advanced Python by Studying Open Source Projects 1st Edition Li - The Latest Updated Ebook Version Is Ready For Download

The document promotes the ebook 'Learning Advanced Python by Studying Open Source Projects' by Rongpeng Li, which aims to provide practical insights into advanced Python programming through real-world examples from open source projects. It emphasizes a hands-on approach to learning key concepts such as data structures, algorithms, and object-oriented programming, making it suitable for both beginners and experienced programmers. The book is part of a series focused on Python and its applications in various fields, and it is available for instant download in multiple formats.

Uploaded by

kinyuyhomans
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views60 pages

Learning Advanced Python by Studying Open Source Projects 1st Edition Li - The Latest Updated Ebook Version Is Ready For Download

The document promotes the ebook 'Learning Advanced Python by Studying Open Source Projects' by Rongpeng Li, which aims to provide practical insights into advanced Python programming through real-world examples from open source projects. It emphasizes a hands-on approach to learning key concepts such as data structures, algorithms, and object-oriented programming, making it suitable for both beginners and experienced programmers. The book is part of a series focused on Python and its applications in various fields, and it is available for instant download in multiple formats.

Uploaded by

kinyuyhomans
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 60

Explore the full ebook collection and download it now at textbookfull.

com

Learning Advanced Python by Studying Open Source


Projects 1st Edition Li

https://textbookfull.com/product/learning-advanced-python-
by-studying-open-source-projects-1st-edition-li/

OR CLICK HERE

DOWLOAD EBOOK

Browse and Get More Ebook Downloads Instantly at https://textbookfull.com


Click here to visit textbookfull.com and download textbook now
Your digital treasures (PDF, ePub, MOBI) await
Download instantly and pick your perfect format...

Read anywhere, anytime, on any device!

Firm Sponsored Developers in Open Source Software Projects


A Social Capital Perspective Dirk Homscheid

https://textbookfull.com/product/firm-sponsored-developers-in-open-
source-software-projects-a-social-capital-perspective-dirk-homscheid/

textbookfull.com

Deep Learning for Remote Sensing Images with Open Source


Software 1st Edition Rémi Cresson

https://textbookfull.com/product/deep-learning-for-remote-sensing-
images-with-open-source-software-1st-edition-remi-cresson/

textbookfull.com

How Open Source Ate Software: Understand the Open Source


Movement and So Much More Gordon Haff

https://textbookfull.com/product/how-open-source-ate-software-
understand-the-open-source-movement-and-so-much-more-gordon-haff/

textbookfull.com

How Open Source Ate Software: Understand The Open Source


Movement And So Much More Gordon Haff

https://textbookfull.com/product/how-open-source-ate-software-
understand-the-open-source-movement-and-so-much-more-gordon-haff-2/

textbookfull.com
Penetration Tester's Open Source Toolkit Faircloth

https://textbookfull.com/product/penetration-testers-open-source-
toolkit-faircloth/

textbookfull.com

Reinforcement Learning: With Open AI, TensorFlow and Keras


Using Python 1st Edition Abhishek Nandy

https://textbookfull.com/product/reinforcement-learning-with-open-ai-
tensorflow-and-keras-using-python-1st-edition-abhishek-nandy/

textbookfull.com

PostgreSQL Up and Running A Practical Guide to the


Advanced Open Source Database Regina O. Obe

https://textbookfull.com/product/postgresql-up-and-running-a-
practical-guide-to-the-advanced-open-source-database-regina-o-obe/

textbookfull.com

Python machine learning blueprints intuitive data projects


you can relate to an approachable guide to applying
advanced machine learning methods to everyday problems
Alexander T. Combs
https://textbookfull.com/product/python-machine-learning-blueprints-
intuitive-data-projects-you-can-relate-to-an-approachable-guide-to-
applying-advanced-machine-learning-methods-to-everyday-problems-
alexander-t-combs/
textbookfull.com

Studying Babies and Toddlers Relationships in Cultural


Contexts 1st Edition Liang Li

https://textbookfull.com/product/studying-babies-and-toddlers-
relationships-in-cultural-contexts-1st-edition-liang-li/

textbookfull.com
Learning Advanced Python by
Studying Open Source Projects
This book is one of its own kind. It is not an encyclopedia or a hands-on tutorial that traps
readers in the tutorial hell. It is a distillation of just one common Python user’s learn-
ing experience. The experience is packaged with exceptional teaching techniques, careful
dependence unraveling and, most importantly, passion.
Learning Advanced Python by Studying Open Source Projects helps readers overcome the
difficulty in their day-to-day tasks and seek insights from solutions in famous open source
projects. Different from a technical manual, this book mixes the technical knowledge, real-
world applications and more theoretical content, providing readers with a practical and
engaging approach to learning Python.
Throughout this book, readers will learn how to write Python code that is efficient,
readable and maintainable, covering key topics such as data structures, algorithms, object-
oriented programming and more. The author’s passion for Python shines through in
this book, making it an enjoyable and inspiring read for both beginners and experienced
programmers.

Rongpeng Li (Ron) is a YouTube educator and animator. He has a consistent passion for
education. He has published two books on statistics and scientific simulation.
Chapman & Hall/CRC
The Python Series

About the Series


Python has been ranked as the most popular programming language, and it is widely used
in education and industry. This book series will offer a wide range of books on Python
for students and professionals. Titles in the series will help users learn the language at an
introductory and advanced level, and explore its many applications in data science, AI, and
machine learning. Series titles can also be supplemented with Jupyter notebooks.

Image Processing and Acquisition using Python, Second Edition


Ravishankar Chityala, Sridevi Pudipeddi
Python Packages
Tomas Beuzen and Tiffany-Anne Timbers
Statistics and Data Visualisation with Python
Jesús Rogel-Salazar
Introduction to Python for Humanists
William J.B. Mattingly
Python for Scientific Computation and Artificial Intelligence
Stephen Lynch
Learning Professional Python
Usharani Bhimavarapu and Jude D. Hemanth
Learning Advanced Python by Studying Open Source Projects
Rongpeng Li

For more information about this series please visit: https://www.crcpress.com/Chapman--


HallCRC/book-series/PYTH
Learning Advanced Python by
Studying Open Source Projects

Rongpeng Li
Cover image: Rongpeng Li

First edition published 2024


by CRC Press
2385 Executive Center Drive, Suite 320, Boca Raton, FL 33431

and by CRC Press


4 Park Square, Milton Park, Abingdon, Oxon, OX14 4RN

CRC Press is an imprint of Taylor & Francis Group, LLC

© 2024 Rongpeng Li

Reasonable efforts have been made to publish reliable data and information, but the author and publisher cannot
assume responsibility for the validity of all materials or the consequences of their use. The authors and publishers
have attempted to trace the copyright holders of all material reproduced in this publication and apologize to
copyright holders if permission to publish in this form has not been obtained. If any copyright material has not been
acknowledged please write and let us know so we may rectify in any future reprint.

Except as permitted under U.S. Copyright Law, no part of this book may be reprinted, reproduced, transmitted, or
utilized in any form by any electronic, mechanical, or other means, now known or hereafter invented, including
photocopying, microfilming, and recording, or in any information storage or retrieval system, without written
permission from the publishers.

For permission to photocopy or use material electronically from this work, access www.copyright.com or contact the
Copyright Clearance Center, Inc. (CCC), 222 Rosewood Drive, Danvers, MA 01923, 978-750-8400. For works that are
not available on CCC please contact [email protected]

Trademark notice: Product or corporate names may be trademarks or registered trademarks and are used only for
identification and explanation without intent to infringe.

Library of Congress Cataloging-in-Publication Data


Names: Li, Rongpeng, author.
Title: Learning advanced Python from open source projects / Rongpeng Li.
Description: Boca Raton, FL : CRC Press, 2024. | Series: Chapman & Hall/CRC
the Python series | Includes bibliographical references and index.
Identifiers: LCCN 2023024040 (print) | LCCN 2023024041 (ebook) |
ISBN 9781032328164 (paperback) | ISBN 9781032328188 (hardback) |
ISBN 9781003316909 (ebook)
Subjects: LCSH: Python (Computer program language) | Open source software.
Classification: LCC QA76.73.P98 L49 2024 (print) | LCC QA76.73.P98
(ebook) | DDC 005.13/3—dc23/eng/20230725
LC record available at https://lccn.loc.gov/2023024040
LC ebook record available at https://lccn.loc.gov/2023024041

ISBN: 978-1-032-32818-8 (hbk)


ISBN: 978-1-032-32816-4 (pbk)
ISBN: 978-1-003-31690-9 (ebk)

DOI: 10.1201/9781003316909

Typeset in Minion
by codeMantra
To Yan, the brightest light in my life.
To my family, whose decisions made my life today possible.
To Holly and Prosper, the endless source of joy in the room.
Contents

Preface, x
Acknowledgments, xi

IntroductIon 1
PURPOSE AND SCOPE OF THIS BOOK 1
OVERVIEW OF THE APPROACH TAKEN 3
NOTE 4

C
A GENTLE INTRODUCTION TO PYTHON’S DATA MODEL 5
CUSTOMIZED COMPARISON 7
A MANAGED ITERATION BEHAVIOR 12
ATTRIBUTES, FUNCTION OR DICTIONARY? 16
SUMMARY 20
NOTES 20

C
INTRODUCTION 21
DESCRIPTORS AND ATTRIBUTE LOOKUP ORDER 21
Descriptor Demystified 21
Lazy Evaluation in Matplotlib 25
METACLASS AND ITS USAGE IN ELASTICSEARCH DSL 30
Understanding Metaclass Using Meta-Recipe 30
Use Metaclass to Model Documents in Elasticsearch DSL 35
SUMMARY 40
APPENDIX 40
NOTES 41
viii   ◾    Contents

C
CONCURRENCY FROM A TOP-DOWN PERSPECTIVE 42
Operating System and Concurrency 45
Introducing Global Interpreter Lock (GIL) 47
MULTIPROCESSING FOR CPU BOUND TASKS 48
Parallel Pandas Apply in pandarallel 52
MULTITHREADING FOR I/O BOUND TASKS 58
SUMMARY 63
NOTES 63

C
A SHIFT OF PARADIGM 64
EVENT-DRIVEN SIMULATION 65
ASYNC AS A PATTERN 71
SUMMARY 75
APPENDIX 75
NOTES 76

C
INTRODUCTION 77
THE DECORATOR FOR RETRYING A FUNCTION 77
CONTEXT MANAGER IN A NUTSHELL 81
DIVE INTO THE AIOSQLITE EXAMPLE 84
Connection as an Executor and a Scheduler 85
Connection and Cursor as Async Context Managers 88
SUMMARY 93
NOTES 93

C
UNDERSTAND YOUR BUSINESS 94
A Quick Overview of the Business 95
MODEL THE BUSINESS ENTITIES WITH OOP 97
Design the Core Entities 97
Establish the Relationship between Classes 100
The Benefits of Universal interface 104
Sometimes No OOP is the Best Design 106
Contents   ◾    ix

SUMMARY 108
NOTES 108

C
INTRODUCTION 109
FIXTURE AND PARAMETERIZATION 109
Parameterization 111
Resources and Fixture 113
MONKEY PATCH 115
Modify the Built-in Print 115
More Powerful Monkey Patching 117
PROPERTY-BASED TEST 118
SUMMARY 122
NOTES 122

INDEX, 123
Preface

I am very excited and happy to present this book to you.


This book is somewhat like my previous two books. Not because they share similar
topics, but because I wrote it with a vivid image of readers in my mind. In my opinion, a
book like this should have existed long before: there are tons of great open source Python
projects, and there are a lot of people who find it hard to learn advanced Python topics. It is
natural to have a book that seamlessly bridges the golden resources and the hungry learn-
ers. This book is it. When I tried to learn from the pros, I did it the hard way by bashing
my head and absorbing much-alike materials from 20 browser tabs. Looking back, I think
there are better ways to do it: an educational and instructional way. My experience as an
instructor helped me a lot in writing this book: I am able to put my feet in the learners’
shoes.
I am very grateful to the editors at Taylor & Francis who helped me identify and con-
firmed the value of this approach. I hope you find this experimental approach educational,
accessible and entertaining.

x
Acknowledgments

I would like to thank the creators, maintainers and all contributors to the open source
projects I used as examples in this book.
It is unimaginable if those amazing resources are not freely accessible to me and to
everyone around the globe. The open source movement has astronomically impacted not
only the software engineering but also the advance of technology universally.
Thank you, from the bottom of my heart.

xi
Introduction

PURPOSE AND SCOPE OF THIS BOOK


Learning Advanced Python by Studying Open Source Projects is a book that is written for
95% of Python users, covering 95% of their daily use cases.
What does this mean?
From the content perspective, it means that this book is not an encyclopedia that covers
everything. It covers all the important things for most Python users.
Based on my observations and research, the following topics are considered important:

1. The Python data model

3. Concurrency and asynchronous programming


4. Functions and related tips
5. How to design an OOP system

They are important in different ways.

1. The Python data model and Python classes are fundamentally important as they are
the basics to learn everything else. They are basic but they are not obviously easy to
master. Many Python users, or most Python users didn’t graduate with a computer
science master’s degree. They started using Python by copying and pasting so long as
the code worked. At some point in their learning or career path, the lack of founda-
tion will bite. I want to solidify your foundations.
2. The other four topics are deemed as a gap between so-so engineers and more pro-
fessional engineers. I picked these four because they are the ones that I find easy to
break the cyclic dependencies of the advanced topics. For example, it is impossible
to talk about concepts like fixture without talking about decorators first. It is hard

DOI: 10.1201/9781003316909-1 1
2   ◾    Learning Advanced Python by Studying Open Source Projects

to imagine context manager without talking about the idea of coroutine first: well
technically you can. I try to chop the open source projects that utilize multiple such
concepts into digestible pieces. The example of aiosqlite is probably the most typical
example. Please do read Chapter 5 and let me know whether I did an acceptable job.

The following topics are not considered important enough for most readers.

2. Publishing a Python package

Well, those topics are very important if you are working on fine-tuning Python perfor-
mances: not because of bad code but because of Python itself. For example, some high-
performance computing work requires such skills, but most Python users don’t ever write
a line of C in their whole career. Similarly, most people don’t publish Python packages as
well.
There are great resources on these two topics. I would recommend the official doc for the
former and the book Publishing Python Packages1 by Dane Hillard for the latter. Honestly
speaking, the fact that the second topic is enough for an independent book also makes it
impractical to be included in this book. The first topic is also big enough for an indepen-
dent book.
The following topics are indeed important, but they are not really Python specific.

The first draft of this book included documentation as an independent chapter. Popular
Python open source libraries often have fabulous documentation. However, the more I
wrote about it, the more I feel that they are not advanced Python, they are skills related to
advanced Programming. Everyone who wrote code needs to know them. It is not suitable to
include them in a book about Python.
Similar ideas apply to project management. Since most open source projects are devel-
oped for the public, you can read the comments, the interactions and sometimes spicy
exchanges between developers and users. I personally find this topic super interesting while
preparing the materials. However, they are, again, not Python specific. I have to drop it.
Let’s discuss the purpose of this book. This book’s purpose is to help moderately good
Python users to become professional Python users.
What is a Python user? What is moderately good? What makes a Python user
professional?
A Python user is a superset of a Python developer. When I was a PhD student, I used
Python a lot. I was not a Python developer. Namely, I wrote Python as a tool to do some-
thing else, rather than for the sake of writing Python. On the contrary, a Python devel-
oper’s job is to write high-quality Python applications.
Introduction  ◾    3

However, I find Python users’ work often requires very high technical skills. For exam-
ple, a Jupyter Notebook is far from enough for a researcher. The researchers sometimes
hack their way through the development and write terrible code. This book aims at the
aspirational and ambitious Python users so they can use Python in the most efficient way.
Of course, developers are welcome.
So, what is exactly being moderately good that qualifies you to read this book?
If you

2. are familiar with basic object-oriented programming concepts like class, instance
and inheritance.
3. understand basic operating system concepts like process, thread and memory.
4. are familiar with tools/platforms like Git, GitHub and VS Code.

Then, you are considered moderately good. Sounds easy, right?


What makes a Python user professional? This is important as it is what you will gradu-
ally learn to become while reading this book.
A professional user can, not limited to the list though, perform the following tasks:

1. read code written by others efficiently and correctly.


2. write more robust, elegant and well-tested Python code.
3. have a deep understanding of Python’s data model and use it appropriately.
4. know how to design an OOP system and turn it into reality.

I hope this gives a good idea of what topics this book covers, and what kind of prerequisites
I am expecting the readers to have.

OVERVIEW OF THE APPROACH TAKEN


One of the biggest features of this book is that it is not written in a textbook style. Instead,
it is written somewhat like a novel as long as the circumstance permits.
In a textbook, the author introduces the concepts, then the theorems, then the solved
examples, followed by exercises.
In a novel, a character doesn’t get on the stage until it is time for the character. The plot
has its own rhythm, and characters have natural development paths.
In this book, concepts and best practices are not introduced until it becomes evident
and obvious that they are absolutely needed. For example, the idea of mixin is not intro-
duced until we find the class relationship in scikit-learn becomes error-prone and unman-
ageable. This is how humans learn. Newton’s laws are not written as a bullet list. They are
discovered after countless observations, experiments and calculations.
4   ◾    Learning Advanced Python by Studying Open Source Projects

Here is another more detailed example.


You want to write a test that tests whether the tested function writes some output to the
screen. You are not sure how to do it so you Google it.
Google returns some links and you click in. Several pages mention the idea of monkey
patch but the code examples in the StackOverflow links are so complex that you can’t use
them directly. You try to read the official docs and it is so long. You try to search on GitHub
but there are decorators on top of decorators with weird syntax. You give up.
What this book offers is a guidance to smoothen the path from the problem to the
answer. I will explain why monkey patch is introduced in testing, what problems it tries to
resolve and how it solves it. I have carefully designed the order of the topics in this book
so you will already have a good grasp of the Python data model before using the, say,
setattr() function doing monkey patching. Then I will show you that the problems you
are facing also exist in the big-name open source projects. We will study how they solve the
problems and the solution to your own problem will be self-revealing.
I do acknowledge that sometimes the order has to be reversed if the example in the open
source project is too complex to absorb at the beginning. I will provide a solution to your
problems first then move on to the open source counterparts.
Again, I am very excited that you picked up this highly experimental book. I hope you
enjoy it and I look forward to your feedback.

NOTE
Chapter 1

The Data Model of Python

A GENTLE INTRODUCTION TO PYTHON’S DATA MODEL


Have you wondered what makes a Python dict a dictionary, and what makes a Python
list a list? In Python, you can perform different kinds of operations on different kinds
of data structures. Take a list, for example, you can append a member to a list, extend
one list with another one and index it with integers. Let’s build a list of cars with code
snippet 1.1.

cars = list()
cars.append(‘bmw’)
cars.extend([‘audi’, ‘toyota’])
assert cars[0] == ‘bmw’
last_car = cars.pop()
assert last_car == ‘toyota’
assert len(cars) == 2

CODE 1.1 Operations on a Python list object.1

For a dictionary, you can perform a different set of operations as shown in code snippet
1.2. You can get a member of the dictionary. Note that both list and dict support the
len() method.

fruit_prices = dict()
fruit_prices[‘apple’] = 0.5
fruit_prices[‘orange’] = 0.25
assert len(fruit_prices) == 2
assert fruit_prices.get(‘pear’) == None

CODE 1.2 Operations with a Python dict object.

What makes lists and dictionaries behave in different ways? What if we want to modify
their behaviors and create a hybrid data structure to suit our needs? This will be the main
topic of this chapter: the data model2 for built-in Python data types.
DOI: 10.1201/9781003316909-2 5
6   ◾    Learning Advanced Python by Studying Open Source Projects

In Python, everything is an instance of the object class. You can think of object as the
ancestor of all things in Python, including the built-in types like int, str, list,
dict and all user-defined classes. Let’s try some examples with code snippet 1.3.

isinstance(“California”,object)
# True

isinstance(int,object)
# True

isinstance(list(),object)
# True

class Car:
pass

isinstance(Car(),object)
# True

isinstance(Car, object)
# True

CODE 1.3 Check the objects’ types with isinstance() function.

A Car instance is an object instance. Also, the Car class itself is an object instance. The
question is that if all stuffs are instances of the object class, then what makes a list dif-
ferent from a dict?
Let’s check the supported methods of a list and a dict.
The dir() function returns a list of attributes and methods supported by an object. We
sort the list in alphabetical order to make it easier to compare the results. Code snippet 1.4
shows the result for a list instance.

sorted(dir(list()))

# [‘__add__’, ‘__class__’, ‘__class_getitem__’, ‘__contains__’,


‘__delattr__’, ‘__delitem__’, ‘__dir__’, ‘__dir__’, ‘__doc__’,
‘__eq__’, ‘__format__’, ‘__ge__’, ...] # skipped

CODE 1.4 The attributes and methods supported by a Python list object.

Let’s check what methods are supported by a list instance but not supported by a dict
instance and vice versa. To do that, we need to build two sets and take a difference as
shown in code snippet 1.5.

set(dir(list())) - set(dir(dict()))
The Data Model of Python  ◾    7

# {‘__add__’, ‘__iadd__’, ‘__imul__’, ‘__mul__’, ‘__rmul__’,


‘append’, ‘count’, ‘extend’, ‘index’, ‘insert’, ‘remove’,
‘reverse’, ‘sort’}

# the other way around

set(dir(dict())) - set(dir(list()))
# {‘__ior__’, ‘__or__’, ‘__ror__’, ‘fromkeys’, ‘get’,
‘items’, ‘keys’, ‘popitem’, ‘setdefault’, ‘update’, ‘values’}

CODE 1.5 Compare the differences of supported methods for a list and a set.

You may notice that both list and set support the __gt__ methods. It means that you
can compare two lists or two dictionaries. It seems that they follow the same protocol here
that defines what they can do: they can be compared against their own kinds.
However, a list supports the __add__ method while a dict instance does not. This
hints that they follow different protocols: lists can be added directly, while dictionaries
cannot.
In the following sections, you will learn how to create your own data structures that fol-
low different protocols and control exactly how they behave.

CUSTOMIZED COMPARISON
Let’s begin with a scenario. You are hired by a major car dealer to create an application that
will help them to keep track of their customers’ information. One key feature of the applica-
tion is to compare the in-house creditability of customers. For example, if two customers
bid for the same car, the application needs to tell your boss which customer is more credible.
We need a Customer class. Code snippet 1.6 creates it.

class Customer:
def __init__(self, first_name: str, last_name: str, credit_
score: int, credit_limit: int, in_debt: bool, monthly_income: int):
self.first_name = first_name
self.last_name = last_name
self.credit_score = credit_score
self.credit_limit = credit_limit
self.in_debt = in_debt
self.monthly_income = monthly_income

def __repr__(self):
debt_status = “not in debt” if self.in_debt == False else
“in debt”
return f”Customer {self.first_name} {self.last_name},
{debt_status},” \
f” with a credit score of {self.credit_score},”\
f” credit limit of {self.credit_limit}” \
f” and a monthly income of {self.monthly_income}.”
8   ◾    Learning Advanced Python by Studying Open Source Projects

f”with a credit score of {self.credit_score},”\


f”credit limit of {self.credit_limit}” \
f”and a monthly income of {self.monthly_income}.”

CODE 1.6 The Customer class.

The __repr__ method is used to print the object. If you don’t define it, Python will print
the object’s memory address like < __main__.Customer object at0x1083c4ee0>.
We can create a few customers and play around with them as shown in code snippet 1.7.

john_smith = Customer(“John”, “Smith”, 800, 200000, False, 10000)


richard_dawkins = Customer(“Richard”, “Dawkins”, 700, 240000,
True, 8000)
albert_jackson = Customer(“Albert”, “Jackson”, 700, 250000, True,
12000)
melissa_miller = Customer(“Melissa”, “Miller”, 700, 250000, False,
9000)

print(melissa_miller)
# Customer Melissa Miller, not in debt, with a credit score of
700, credit limit of 250000 and a monthly income of 9000.

CODE 1.7 Create a few customers and print one out.

To compare the financial credibility of the customers, the car dealer has created a set of
rules based on their historical experiences. The rules are organized in order such that the
rules are checked in order. These rules are:

1. The customer with a higher credit score is more credible.


2. When credit scores are equal, the customer with a higher credit limit is more credible.
3. When both are equal, the customer with a higher monthly income is more credible.

However, if the one who gets paid higher is in debt while another who gets paid lower is
not, the difference of monthly income must be larger than 4000. Otherwise, the one who
is not in debt is more credible.
Ideally, we want to compare the john _ smith and richard _ dawkins objects in
code snippet 1.8. However, we can’t do it because Customers don’t support such operations.

john_smith < richard_dawkins


# Traceback (most recent call last):
# File “FILE_PATH”, line 25, in <module>
# john_smith < richard_dawkins
# TypeError: ‘<’ not supported between instances of ‘Customer’ and
‘Customer’

CODE 1.8 Comparison is not supported for the Customer class.


The Data Model of Python  ◾    9

We have two solutions. One is to write a helper function that compares two customers.
Every time we need to compare customers, we can pass the function to something like the
key parameter of the sort() method. Another solution is to enable native support for
Customer comparison.

Which solution is better? The logic of comparison needs to go somewhere in the code. The
question is where. The canonical way is in the Customer class. There are two reasons. First,
by enabling syntax like john _ smith < richard _ dawkins, we aligned our syntax with
the Pythonic way of doing comparison. It is much easier for your coworkers to integrate the
code into their projects. Second, the built-in comparison logic is more robust and error-free
than a standalone function. When you ship your code to someone else, you have a better
control over the code unless the code users deliberately overwrite the comparison logic in
the Customer class, which is much less likely than them writing another standalone com-
parison function.

Let’s pause our concerns for a while to learn from the pros and see how this is done in
the SymPy library. SymPy is an open source Python library for symbolic computation.
It can be used to perform algebraic computations and symbolic differentiation, etc. Code
snippet 1.9 shows a differentiation example.

import sympy as sym


x = sym.symbols(“x”)
print(type(x))
# <class ‘sympy.core.symbol.Symbol’>
print(sym.diff(x**2+sym.sin(x) + 2*x,x))
# 2*x + cos(x) + 2

CODE 1.9 Use SymPy to calculate the derivative of a function.

In snippet 1.9, we defined a symbol x and differentiated the expression x 2 + sin( x ) + 2 x,


the result is correct: 2 x + cos ( x ) + 2.
Like our cases, customized comparisons are also common in SymPy. For example, a
polynomial’s terms can be arranged in any order, but the polynomial remains the same.
We would love to enable such mathematical expression comparison.
In Python, magic methods or dunder methods like __lt__ and __ge__ define how
comparisons are done. The first stands for less than, and the latter stands for greater than
or equal to. Redefining them, in other programming languages, is often called operating
overloading.

Dunder is an abbreviation of double underscore if you are wondering.

Back to SymPy, instead of studying its implementation, let’s investigate a bug to pierce
into its core. The developers found a bug that alternating two objects’ order in comparison
10   ◾    Learning Advanced Python by Studying Open Source Projects

gives different results in early 2021. As stated in issue 20796,3 the two comparisons in code
snippet 1.10 should both return False. Based on the types of them, one represents numeri-
cal value and another logical. Objects with different data types should always be different.

from sympy import S

S(0.0) == S.false
# True

S.false == S(0.0)
# False

CODE 1.10 Singleton comparisons in SymPy.

S here stands for Singleton. S.false means that there is only one such thing as a math-
ematical false in the whole mathematical universe. There can only be one false and there
can only be one 0.

In object-oriented programming, a singleton is a design pattern that restricts the instantiation


of a class to a single instance and ensures that there is a global point of access to that instance.
S.EmptySet is a singleton example that represents THE mathematical empty set. It is
handy to use a singleton object to represent a special value in mathematics because this empty
set is just that empty set, there are no two different empty sets nor two different infinities.

Now, let’s get to the implementation of the __eq__ method of the S class. Pull request
208014 fixed the issue but I already copied the pre-PR implementation to snippet 1.11.
In snippet 1.11, the self represents a float number.

def __eq__(self, other):


from sympy.logic.boolalg import Boolean
try:
other = _sympify(other)
except SympifyError:
return NotImplemented
if not self: # comment 1
return not other
if isinstance(other, Boolean): # comment 2
return False
if other.is_NumberSymbol:
if other.is_irrational:
return False
return other.__eq__(self)
if other.is_Float:
# comparison is exact
# so Float(.1, 3) != Float(.1, 33)
The Data Model of Python  ◾    11

return self._mpf_ == other._mpf_


if other.is_Rational:
return other.__eq__(self)
if other.is_Number:
ompf = other._as_mpf_val(self._prec)
return bool(mlib.mpf_eq(self._mpf_, ompf))
return False # Float != non-Number

CODE 1.11 Equality comparison of a float number with a bool, before pull request
20801.

The __eq__ method takes two arguments, the first one is the object itself and the second
one is the object to be compared with. When you write comparison like A == B, The __eq__
method of the object on the left side of the comparison is called: in the example, A.
In the line denoted with comment 1, we first check the Boolean representation of the
object itself. If it is False, it means the object is a 0, probably with arbitrary precision. In that
case, we check the other object. If it is also equivalent to 0, then they are equal.
In the line denoted with comment 2, we check whether the other object is a Boolean
object or not. If it is, then we always return False. A number is never the same with a
Boolean, mathematically.
A quick note if you are not catching up. How did we know that the float number’s __eq__
method is wrong? Since S.false == S(0.0) gives the correct answer, which is False, we
then know the S.false. __eq __(S(0.0)) returns the right answer. This is how we know
that the issue is in the implementation of __eq__ for the float number Singleton object.
The devil lies in the order of the two lines I commented. When a float number is equiva-
lent to 0, not self in the first if statement is evaluated to be True, therefore if the other object
is a False object, a True value is returned. These two if statements need to be switched. If
the types are different, then they are never equivalent. This is exactly what the pull request
20801 fixes.
Notice that the practice is very similar to our proposed implementation of __lt__
or __gt__ methods for the Customer class. The order of criteria matters.
Go back on our original question, code snippet 1.12 is implements the __lt__ method
for the Customer class. It is probably the most elegantly written code. In production,
make sure you write comprehensive tests, too.

def __lt__(self, other):


income_threshold = 4000
if self.credit_score != other.credit_score:
return self.credit_score < other.credit_score

if self.credit_limit != other.credit_limit:
return self.credit_limit < other.credit_limit
income_diff = abs(self.income - other.income)

if self.monthly_income < other.monthly_income:


12   ◾    Learning Advanced Python by Studying Open Source Projects

if not self.in_debt and other.in_debt:


return income_diff > income_threshold
return True
elif self.monthly_income > other.monthly_income:
if self.in_debt and not other.in_debt:
return income_diff < income_threshold
return False
else:
return False

CODE 1.12 Implementation of the less than logic for Customer class.

This dunder method allows users to sort customers natively as shown in code snippet 1.13.

john_smith > richard_dawkins


# True

sorted([john_smith, richard_dawkins, albert_jackson, melissa_


miller])[0] == albert_jackson
# True

CODE 1.13 Customer instances can be compared directly now.

So far everything looks great. Let’s do something even fancier in the next section.

A MANAGED ITERATION BEHAVIOR


Summarizing our first lesson, we get a taste that Python objects, whether built-in or user-
defined, can implement or fulfill different protocols.
I am being a little lazy with words here to deviate the definition of protocol from a rig-
orous computer science sense. It basically means a set of rules that defines the behaviors
of an object. For example, if you define a Customer class with a method change _
credit _ limit(), then we have a rule that says that a Customer object can change its
credit limit without caring much how it is implemented.
Python’s built-in data structures implement different protocols. The collections.
abc5 module provides abstract base classes for containers that obey a set of protocols. Here
are a few examples from this module.

1. Sequence: a sequence is a sequence of members.


2. MutableSequence: a sequence whose members can change.
3. Mapping: immutable map from keys to values.
4. MutableMapping: a Mapping that the mapping relationship can be changed.
The Data Model of Python  ◾    13

Please be aware of the difference between the abstract base class and the abstract base class
for containers. The former is a superset of the latter. The abstract base classes in Python also
include those from the numbers module and the io module, etc.

Each abstract class is required to have a specific set of abstract methods. A realization of
one of those abstract classes must implement the corresponding abstract methods.
The abstract classes also have inheritance relationships. For example, the Reversible
abstract class is a subclass of the Iterable abstract class. Therefore, besides the iter()
method, the Reversible class also defines the reversed() method. The Sequence
abstract class is a subclass of both the Reversible and the Collection abstract classes.
Therefore, the Sequence class also needs to define the len() method and the contains()
method to support the in operator, as you often see in the for loop statements.
By the courtesy of Sangmoon Oh, the inheritance relationship between abstract base
classes for containers can be visualized as a hierarchy as shown in Figure 1.1. You can find
his blog on Medium.6
The reason we are interested in the hierarchy of abstract classes is that sometimes we
need to create our own hybrid or Frankenstein classes. Here is the continuation of the car
dealership example.
Your employer, the car dealer, is pleased with your work. Now, the managements want
you to create an application to store and retrieve customer data according to their VIP
status. After some analysis, you identify that you need a data structure to support the

FIGURE 1.1 The class hierarchy of abstract base classes for containers.
14   ◾    Learning Advanced Python by Studying Open Source Projects

following requirements. Let’s call such a data structure CustomerStruct, which is


essentially a container of Customers.

1. A CustomerStruct should support membership tests in O (1) time.


2. A CustomerStruct should support insertion, deletion and union efficiently.
3. A CustomerStruct should support iteration in a special way that it always returns
the VIP customers first.

If a new car is available, the car dealer can iterate through VIP customers first to give them
privileges to choose first. The CustomerStruct should largely behave like a set. Among
all the common data structures, only dictionaries and sets support membership tests in
O (1) time. Since we are not looking up for data, a set is enough. The issue with a default
set is that its iteration is not in any particular order after some member manipulation.
However, you should know that since Python 3.7, the default dict data structure is inser-
tion-ordered if you iterate over a dictionary. I will quote from the Python documentation:

A set is an unordered collection with no duplicate elements. Basic uses include membership
testing and eliminating duplicate entries. Set objects also support mathematical operations
like union, intersection, difference and symmetric difference.

We don’t want to implement an ordered set completely because we don’t prefer one VIP
customer over another or one non-VIP customer over another. If you are interested in a
fully functional ordered set, you can check the ordered sorted container Python library.7
The problem then boils down to the implementation of the __iter__ method which
dictates the behavior of iteration. Interestingly, the SymPy developers faced a similar con-
cern like ours. They want to implement the rational number set and allow callers to iterate
over the set in a specific way. Why? Recall that a rational number is any number that can
1 3
be represented as a fraction. For example, , are both rational numbers while π , the ratio
2 5
of a circle’s circumference to its diameter, is not. The rational number set is also infinitely
large. Iterating over such an infinite set exhaustively and reasonably is their concern.
The source code is in the sympy.sets.fancysets.Rationals class as shown in
code snippet 1.14.

def __iter__(self):
from sympy.core.numbers import igcd, Rational # comment 1
yield S.Zero
yield S.One
yield S.NegativeOne
d = 2
while True:
for n in range(d):
The Data Model of Python  ◾    15

if igcd(n, d) == 1: # comment 2
yield Rational(n, d)
yield Rational(d, n)
yield Rational(-n, d)
yield Rational(-d, n)
d += 1

CODE 1.14 Generate all rational numbers systematically.

In the line denoted with the first comment, they used a function called igcd() to deter-
mine whether two numbers are relatively prime. The Rational class is used to build a
rational number. Two rational numbers are essentially the same if one can be reduced to
1 23
another. For example, is essentially equivalent to . Several Singleton objects are being
2 46
yielded in the following lines first. There is only one 0, one positive 1 and one negative 1, etc.
Then the iteration is dictated by increasing a value d, while finding all the possible com-
binations of the pair (n, d ), where n is smaller than d and relatively prime to it.

Notice that the __iter __ method can yield rational numbers indefinitely, which gives you
an idea why protocols are important to write efficient code. The code doesn’t need to be hon-
est if it does what it is supposed to do faithfully, according to the protocol. For example, you
can pass a handler to users to iterate over a large amount of data records from a database. You
don’t want to query so much data beforehand because it is going to be a disaster memory-
wise and time-wise. What you can do is to return a small amount of data for the user to use,
maintain a cursor and defer additional queries until needed. The amortized cost will be low.

Let’s give it a try to check the pattern. I am examining the first 20 results in code snippet
1.15.

for idx, val in enumerate(sympy.Rationals):


if idx < 20:
print(val)
else:
break
# 0
# 1
# -1
# 1/2
# 2
# -1/2
# -2
# 1/3
# 3
# -1/3
# -3
# 2/3
16   ◾    Learning Advanced Python by Studying Open Source Projects

# 3/2
# -2/3
# -3/2
# 1/4
# 4
# -1/4
# -4
# 3/4

CODE 1.15 Use the Rationals class to generate first 20 rational numbers.

Time to go back to our CustomerStruct case. We also need to slightly modify the
Customer class to initiate them with an is _ vip argument (snippet 1.16).

class Customer:
def __init__(self, ..., is_vip: bool)
self.is_vip = is_vip

class CustomerStruct:
def __init__(self, customer_set: set):
self.customer_set = customer_set

def __iter__(self):
for customer in self.customer_set:
if customer.is_vip:
yield customer
for customer in self.customer_set:
if not customer.is_vip:
yield customer

CODE 1.16 Iterate through VIP customers first.

The drawback of this approach is that we will have to loop the customer _ set twice.
Well, there is no free lunch. Better solutions so exist but you get the point.

ATTRIBUTES, FUNCTION OR DICTIONARY?


The flexibility of Python is one of its main strengths, as well as a timed bomb if used
improperly. In the last section, let’s think about a case where we have different approaches
to solve the same problem, although some approaches seem intuitively weird.
A defined instance attribute can be found in the __dict__ dictionary that the instance
maintains. Code snippet 1.17 is an example.

class Customer:
def __init__(self, is_vip: bool):
self.is_vip = is_vip
print(Customer(True).__dict__)
Discovering Diverse Content Through
Random Scribd Documents
közben, társai közül eltünik, de gondoskodva van róla, hogy magát
semmi bajba ne keverje: az erdő, a hol vadászni szokott, hét
mérföldnyi kerületben, katonai őrlánczczal van körülvéve, melyen
sem ki, sem be nem lehet jutni Annius tudta nélkül.
És mégis megtörténik, hogy e körülfogott erdőségben néha úgy
el tud tünni a fejedelemnő, hogy kisérői hetekig sem találják újra föl.
Pedig minden rejtekhelye a bércznek és völgynek fel van már
kutatva, az erdőlakók megvesztegetve, hogy lessenek utána; sőt azt
a fáradságos munkát is megtették már, hogy az elvágtató paripa
nyomán utána mentek; a vezérlő patkónyomok azonban majd egy
sziklaúton, majd egy vízmederben elvesztek s azontul nem lehetett
többé folytatásukra akadni, mintha ég vagy föld rejtette volna el a
lovagnőt paripástól együtt.
Mikor aztán társaihoz visszatért, vagy azok ráakadtak, annyi
bölény szakállát és szarvait látták nyergére fölaggatva, a mennyit ők
valamennyien sem bírtak elejteni. Ez volt tanubizonysága annak,
hogy egész rejtélyes távolléte alatt nem tett mást, mint a vadakat
üldözte s egyedül küzdött velük a berkekben.
Kilencz év alatt Annius megvetett szerelme a boszúálló gyűlöletté
változott át; a nőnek, ki hajolni nem akart, törnie kellett.
Egy napon egy sarmata decurio beszélé előtte a tábortüz mellett
mesélgetve, hogyan szokták az ő nemzetbeliek a bölényt
megkeríteni; felöltöztetik a jó futó paripát hím bölény bőrébe, maga
a lovag szinte a bőr alatt van, úgy hogy a feje, a mint a ló hátán
hasmánt fekszik, a bölény púpját képezi, s ez által tökéletesen azt az
alakot adja a lónak, a mi az idomtalan, vastagderekú bölényé. A
púpon elől nyilás van, melyen a lovag kinéz, s kezeivel a bölény
sörénye alatt igazgatja a ló fékét. Igy a gyanutlanul legelésző
bölénycsorda közepébe juthat s akkor egyszerre hátravetve a rejtő
sörényes bivalyfőt, nyilakkal lelövöldözi áldozatait.
– Hallod-e Balbus, így szólt hozzá a vezér, én te rád egy nagy
feladatot bízok. Eredj abba az erdőbe, az általad leirt álcza alatt, a
hol az angresi asszony vadászni szokott, menj hozzá közel s légy
rajta, hogy figyelmét magadra vond. Én parancsot fogok adni, hogy
mikor ő üldözésedre indul, társai elmaradjanak s engedjék őt
egyedül utánad menni. Te csalogasd őt magad után, s ha elmarad
tőled, fordulj te ismét rá vissza s kövesd nyomról-nyomra, míg
megtudod a titkot, hová szokott ő eltünni e vadászatok alkalmával.
Balbus ügyesen hajtá végre a rábizott alakjátékot. Egy vadászat
alkalmával esti holdvilágnál megjelent a bölény álarcza Eponine
vadásztanyája közelében s a fejedelemnő rögtön paripájára ült s
üldözőbe vette azt.
Az álfenevad hurczolta őt maga után órahosszat erdőkön,
völgyeken keresztül; egyszerre Balbus vevé észre, hogy háta mögött
a csörtetés elmarad s a mint visszafordult, látta, hogy a fejedelemnő
elcsapott nyomáról s lovát kantáron vezetve, gyalog halad egy hegyi
folyam sziklás partján fölfelé, egészen eltérve az iránytól, melyet a
bölény vett.
Most ő is visszafordult s utána kezde menni. Nem szokatlan
tünemény ez, hogy az üldözött bölény vadásza ellen visszacsap s
szerepet cserél vele.
A fejedelemnő nem sokára észrevette a fenevad közeledését,
azonban a helyett, hogy sietett volna lovára kapni, közelre várta azt
s akkor hirtelen előkapva tegzét, egy nyilat küldött eléje.
Balbus érzé, hogy épen arcza mellett vágott be a nyíl. Ha
Eponina a bölény púpjára czéloz, épen Balbus fejébe talál.
A megsebesült mén egyszerre ijedten fordult vissza s vágtatni
kezde tüskön, bokron keresztül, a mit észrevéve Balbus, hirtelen
kicsúszott a bölénybőr alól a ló farán keresztül s azt futni hagyva,
maga a földön kúszva követte a fejedelemnő jártát, mint valami
lappangó hiúz.
A völgy fenekére érve, a hegyi folyam forrása tünt szem elé; fenn
a meredek hegyoldalban eredt az, s négy öles magasról zuhatagot
képezve, omlott egyenesen alá, még csak egy kő sem volt útjában,
melyen megakadjon.
A zuhatagon keresztül valami figyelmesen vizsgáló szem
fölfedezhetett egy embernagyságnyi hasadást a sziklában, s
gyanítható volt, hogy azon belül tán egy mélyebb üreg létezik,
azonban a lecsapó vízoszlop lehetetlenné tette az ahozférhetést,
minthogy épen fedezte a nyílást s a bejutni kivánót kétségtelenül
lezúzta volna.
A mint Eponine e forráshoz ért, levette kürtjét oldaláról s a
barlang nyílásához közel háromszor belefujt; a hangnak igen erősnek
kellett lenni, hogy a zuhatag robaján keresztül meg lehessen hallani.
Erre a kürtszóra úgy tetszék Balbusnak, mintha a vízomlás
zuhogása kevesebb viszhangot költene a völgyben, mintha a
lerohanó vízoszlop vékonyodnék; és valóban lassankint mindig
csendesebb lett a zaj, pihentebb a vízomlás; utóbb csak egy vékony
csergedező sugár maradt fenn belőle, hanem a helyett a
sziklahasadék aljából kezdett el egy új forrás előzuhogni,
kétségtelenül ugyanaz, mely amott a magasban megszünt omolni.
A sarmata kém megborzadt e látványon. A fejedelemnő
bizonyosan egy bűbájos amphisbaenra, ki a földalatti szellemekkel
parancsol, hogy kénye-kedve szerint változtassák a vizek folyását; s
a földön fekve maradt, nem mert tovább közelíteni hozzá, a
bűvésznő szava bizonyosan veszett farkassá változtatná a vakmerőt.
Annyit látott csupán, hogy a mint a zuhatag megállt, Eponine
lovastul együtt leszállt a vízmederbe s lovát maga után vonva, a szűk
barlangnyíláson át a szikla mélyében eltünt.
És azután nem sokára ismét elkezdett csorogni a vízsugár onnan
a magasból; mindig erősebb, mindig hangosabb lett; néhány pillanat
múlva épen oly erőszakos rohammal fedte a barlang nyílását, mint
elébb.
Balbus, ha elég merész lett volna is hozzá, nem követhette a
fejedelemnőt tovább.
A helyett sebten visszafordult s gyalog kivergődve az erdőből,
visszakerült Anniushoz, tudósítva a római vezért azon csodáról, mely
szemei előtt végbement, s esküdött rá, hogy a mely nő szavára a víz
megáll s a szikla meghasad, a víz újra megered s a szikla újra
bezárul, annak nem üdvös halandó fejjel üldözésére elindulni.
Annius pedig többet tudott már az elégnél, s mosolygott kéme
ijedelmén. Az azon korbeli római sok istennek áldozott ugyan, de
egytől sem félt.
***
Annius azonnal kiválasztott húsz férfit a legmerészebb triariusok
közül s a sarmata kém által elvezetteté magát az aranyhegyi
rengetegbe, a zuhatagig.
Négy izmos férfi, egy öblös paizst domború felével fölfelé tartva,
felfogá az omló víz rohamát: a nyílás járható lett.
Annius paizsát előre tartva, jobbjában kivont kardját szorítva,
merészen lépett be az ismeretlen sötétségbe, melyet az aggódók
képzelete varázshatalmú lények csodáival népesíte meg. A
csataedzett triariusok szívdobogva követték vezérüket.
Alig haladtak húsz lépésnyire a szűk torkolaton keresztül, midőn
világosság kezdett szemeik előtt derengni. Ott megállítá harczosait
Annius és csendet inte.
Egy szál szurokfenyőhasáb lobogott fáklyaképen a barlang
mélyén, fényes világot vetve egy boltozatos oldalüregre, mely mint
egy fejedelmi trón padmalya, zászlókkal és fegyverekkel volt
feldiszítve. A boltozat alatt medvebőrökből vetett nyugágy volt
elkészítve; azon a nyugágyon hevert egy férfi, hosszú szőkefürtű
fejét egy tündérszépségű hölgy ölében nyugtatva, lábaiknál két
fiucska játszott, egyik hét éves lehetett, a másik még kisebb; apjuk
kézíját próbálgatták; az elpattant húr meg-megüté a kisebbik gyönge
ujját, de azért nem sírt, csak nevetett rajta; a nagyobbik már jól
megtudta azt vonni.
Annius megismeré Eponinét.
A nő gyöngéden simogatá meg a férfi omló hajfürteit, s oly
szerelmes tekintettel, mint egy nőoroszlán, függött annak deli
vonásain.
– Látod, Sabinus, hogy a föld alatt is van boldogság, suttogá, a
játszó gyermekekre pillantva.
– Még mindig a zsarnoké a föld felszíne?
– Övé az égtől a pokolig minden: csak a sírban lakók mentek
hatalmától.
– S én a sírban lakom.
– Már kilencz év óta.
– Már kilencz év óta nem láttam, hogy mi az a nap? Csak éjjel
járhatok ki a vadakra lesni, a mik a patakhoz jönnek. Úgy óhajtottam
sokszor meglesni a hajnalt, de te megtiltottad azt nekem, s én szót
fogadok. Csak az omló zuhatagon keresztül látom néha a megtört
napfényt szivárványalakban; s mikor te jösz, akkor a te szemeidben.
– Még ez a két gyermek sem látta a napvilágot soha.
– Születésük óta csak csillagfényt és fáklyavilágot ismernek.
– Talán el sem fogják tűrni szemeik a szabad napsugárt.
– Oh a szabad napsugár! sóhajta fel az eltemetett hős, ki ne
éledne fel attól? Melyik halottnak ártana az meg, ha föltámadhatna
újra?
– Csitt, mintha csörrenést hallanék.
– A zsilip fel van húzva; a földalatti víz zuhog a csatornában, a
vízesésen át nem jöhet ide senki.
– Tanítod-e gyűlölni gyermekeidet?
– Oh ez mindennapi imájuk.
– Tudják-e, hogy ők egy király fiai? Mondtad-e nekik, hogy fejük
felett egy haza van és egy korona, mely az övék?
– Hallgasd csak, mit tudnak énekelni?
A két gyermek rögtön felugrott fektéből s kis kardjaikat kapva,
elkezdék a fegyvertánczot, melyre apjuk tanította őket, s éneklék
mellé a harczi dalt gyenge, csengő gyermekhangon:
«Fel, fel a sírból!
Törd le a lánczot!
Kardot a kézbe!
Elleneidnek
Döfd kebelébe!
Vágd a bitorlót!
Hulljon a vére!
Gallia földe
Zöld lesz utána!»

Eponine úgy tapsolt örömében, úgy hullott szeméből a köny.


E pillanatban Annius paizsa csattant; kardja lapjával ráütött, jelt
adva, s a római harczosok előrohantak:
– Sabinus, add meg magad!
A meglepett fejedelmi pár, mint két oroszlán, szökött fel helyéből;
Sabinus hosszú kardját ragadta, Eponine tegzét kapta kezébe, két
gyermekét palástja alá takarva.
Annius a fáklyát emelte föl, mit Sabinus a földre lökött s azt
magasra tartva világított vele harczosainak.
– Fogjátok őket el élve. Római, vigyázz; meg ne ölj egyet is. Ez a
vér Vespasian itala!
Sabinus kardja felel a támadóknak; a padmalymélyedésbe állva,
csupán szemközt lehetett őt megrohanni; s a halottak kardja jól fog.
Paizsát nem használta, nem akarta testét védni, két kézre fogá a
a hosszú pallost, úgy sujta ellenei közé vele. Hatan hevertek már
előtte halva.
Mögötte Eponine állt, s nyilait a közeledőre röpítve, ártó sebekkel
rontá a harczosokat.
– Római, ne légy gyáva! hangzék Annius parancsszava.
Azon pillanatban egy nyíl vágta ki jobb szemét, Eponine kezétől
küldve.
Annius a fájó sebtől nem izgatott aczélhangon kiálta:
– Római, meg ne sebesítsd őket, minden csepp vérük a császáré!
Egy újabb bőszült roham leveré lábáról Sabinust: hosszú kardja
hegyével beleakadt nyugágya takaróiba, ott elnyomták és
megkötözték. Eponine és a két gyermek bilincstelenül követték őt.
Tudja azt a vadász jól, hogy a barlanglakó vad ivadéka fogoly
anyjától el nem szalad.
***
Vespasian udvarában megrendíté a kebleket ez eset híre, mely a
mesékkel és a hajdani Róma erkölcseivel határos.
Hogy egy nő kilencz évig rejtve tudja tartani férjét, s földalatti
rejtekében őt boldogítsa; hogy a világ előtt még azt is el bírja
titkolni, midőn hitvesi szerelme zálogait szíve alatt viselé, kiket nem a
világra, hanem a földalatti sötétségre szült, ott tejével táplált és
fölnevelt, és mindezt nem is gyanítá senki.
Mennyi erőnek kellett azon szívben lenni, hogy a földfeletti fényt,
mely őt gúnyképen környezé, el bírja viselni s minden gondolatában
ahoz térjen vissza, ki a föld alatt van, s e hosszú küzdelemben meg
ne tébolyuljon!
Vespasian halálra itélte őket.
Először csak Sabinusra mondá ki az itéletet; a midőn Eponine azt
kérte, hogy hadd szólhasson ő az imperátorral. Azt hitte, hogy ha
gyermekei könyörgésével egyesítendi a magáét, meglágyíthatja a
császár szívét.
Eléje vezették. Ismerte már azt a termet, azt a trónt, azt az
arczot; kilencz év előtt térdepelt már előtte.
– Vespasian! szólt a nagylelkű hölgy, megalázva büszkeségét,
hogy férjét megszabadítsa. Kilencz év előtt itt könyörögtem előtted
Sabinusért; itt igérted meg, hogy kegyelmet adsz neki. Akkor nem
tartád meg fejedelmi szavadat. Akkor én egyedül voltam, nem
tudtam jól szívedhez szólani. Most nézd, hárman vagyunk; nézd e
két gyermeket, kik azért születtek az örök éjszaka sötétségeiben,
hogy négy ártatlan kézzel több nyuljon trónod elé, esdve Sabinus
életeért! Tekints e gyermekek hozzád emelt arczaiba s azokból
többet fogsz olvashatni, mint a mit az én gyönge szavam mondhat.
Ha vétett ellened Sabinus, kilencz évig halott volt, megbünhödött
érte. Légy te most Isten, ki őt feltámasztod a sírból. Mutasd meg,
hogy Róma császárai nemcsak azért istenek, mert ölni tudnak,
hanem mert éltet is tudnak adni!
Vespasian biborpalástján keresztül nem jutottak e szavak
szívéhez.
– Sabinus özvegye! szólt hozzá szárazon. Én arról, hogy férjed él,
semmit sem tudok, mert te magad mondád, hogy meghalt; és így
szükségkép halva kell neki lenni. Téged és gyermekeidet nem
bántalak, mint hozzátartozóit; egy halottnak nem lehet neje, annál-
kevésbbé gyermekei. Sabinus özvegye, vidd magaddal árváidat. A ki
meghalt, annak halott a neve.
Eponine fölegyenesedék e szóra, s fölrántá gyermekeit, ne
térdeljenek ott. Büszke, daczos arczczal fordult Vespasiánhoz:
– Úgy szóltál, mint egy öszvérhajcsár fiához illett. A szégyen nem
enyim, ki hiába térdeltem előtted, hanem a tied, ki egy könyörgőt
kigunyolál. Vedd vissza a sovány kegyelemszót, mit nekem adtál,
Sabinus élete az én életem is. Boldogabb voltam én a sötét föld
alatt, a hangtalan éj rideg rémei közt tégedet gyűlölve, mint te voltál
itt dicsőséged hazug ragyogásai közt, silány hizelgők napraforgó
arczainál; ki rettegtél legyőzött ellenségedtől, kit már eltemettél.
Gyáva zsarnok, öless meg engem is, hogy nyugton alhass!
Eponine jól számított, ha akarta, hogy férjével együtt haljon. Ily
szavakat az egész udvar hallatára nem lehete megbocsátani.
Vespasian együtt ölette őt meg férjével.
Tán félt tőlük? azért ölette meg?
Oh nem.
Megölette őket azért, mert nem engedheté meg, hogy a magas
római erények, miután Róma falai közül végkép kipusztultak, egy
barbár nemzetnél leljenek menedéket; mert a vas ellen megvéd a
vas, de az eszme és az erény halhatatlan ellensége minden
zsarnokságnak…
14.
FULKÓ LOVAG.
Rege a régi rossz időkből.
Azokban a szomorú időkben, hogy az átkozott kegyetlen tatár
pusztítá e mi jó hazánkat, két jó magyar vitéz testvér, Koppánd
Simon és Koppánd Mikhál, a tamásfalvai pusztulás után, mely nagy
városnak a nyoma sem látszik meg mai nap, valahogy
megszabadultak az égésből, gyilkolásból, s a nádasok közé
menekülve, azokban bújdokoltak sok napon és éjszakán keresztül,
néha fejtetőig elbújva a víz alá, mert a gonosz, vérszomjas ellenség,
még a mocsárokat is meghajtotta, hogy a menekülteket kézrekapja,
nem levén egyéb a szándéka, mint hogy végképen kiirtson minden
magyart a földszinéről.
Ilyenformán, nappal rejtőzködve, éjjel bujdokolva, a szerint
mentek mindig nyugot felé, a mint azt a csillagok járása mutatta
nekik, remélve, hogy még ott menedékre találnak. Eledelük nem volt
ez alatt más, mint a récze- és szárcsatojás, a mit a mocsári
fészkekben kaptak, azzal táplálkoztak.
Egyszer, mikor már nagyon messzire elmentek s azt gondolták,
hogy jóval megelőzték a tatárokat, elő mertek jőni a nádasból a
síkságba s a szép holdvilágnál egy tornyot pillantottak meg jó távol
maguk előtt.
Az ott valami város, gondolák magukban, tartsunk arra; talán ott
biztosságban leszünk, odáig nem jön a tatár. Mert csak azt hitte
minden ember, hogy a mint máskor szokta, egy-egy rablócsorda
betör az országba, s ha jól megszedte magát zsákmánynyal, megint
visszamegy az országába.
Mentek hát a látott torony felé egész éjfélig; hát a mint közel
értek hozzá, akkor vették észre, hogy a toronynak nincsen teteje; a
mint még közelebb mentek, akkor látták, hogy a házak mind földig
vannak rontva, s a mint beértek az utczába, hát akkor látták, hogy
ott senki sem lakik, hanem farkasok és elvadult kutyák üvöltenek
eléjük a fekete kapubálványok mögől, a hol mindenfelé emberek
feküsznek; alakok fej nélkül, asszonyok, nyillal általlőve, az anya, ki
halott gyermekeit takarja holttestével, hosszú, elszórt fekete hajával.
Az ifjak elborzadva takarták el szemeikei e látvány elől, jaj! itt is a
tatár járt már, itt sincs többé élet.
Hanem azért mégis ott akartak maradni másnap éjszakáig,
valahol elrejtőzve, mert már közel volt a reggel, s fényes napvilágnál
nem jó volt kijőni a mezőre.
Bementek hát a templomba, hogy majd ott valahol elrejtőznek,
vagy kriptában, vagy valami sekrestyében.
Hajh! sírbolt volt most az egész templom, ott vágták le a nép
szinét javát, asszony, férfi és gyermek úgy hevert egymáson
keresztül, a leégett gerendák között, a sápadt hold csak úgy
világított le rájuk a tetőtlen orom beszakadt padmalyán át.
Itten valósággal kardot kellett rántaniok, hogy elhajtsák a
farkasokat, a mik a sírásó hivatalát pótolni jöttek ide, s a mint
kiriogatták őket onnan, ismét vissza-visszajöttek s beordítottak az
ajtón.
Azt mondá akkor az öregebbik testvér, Simon: Mikhál öcsém,
ezek a gonosz férgek nekünk itten békét nem adnak, s miattuk meg
nem nyugodhatunk, pedig az álmatlanságtól alig van jártányi erőnk
már; azért te fekügyél le most, az oltár mellett jó helyed lesz, Isten
most is közel van ott még, én majd addig őrt állok az ajtóban s
elhajtom rólad a feneállatokat; majd ha elfáradtam, akkor fölkeltelek
s te fogsz vigyázni rám.
Mikhál tehát keresett valahol egy helyet az oltár mellett, s egyik
holt vitéz mellé lefeküdt, olyan volt mind a kettő, mintha aludnék,
vagy mintha mind a kettő halva volna. Simon vitéz pedig azalatt
összekeresett néhány elhullt nyilat a harczos téren, talált hozzá íjat is
s úgy támaszkodék a puszta ajtófélnek! a mint közeledtek a
toportyán-férgek, közéjük lőtt egy-egy nyilat, a megsebzett aztán
verekedést kezdett a többiekkel, azt gondolva, hogy társai harapták
meg. Ez a rút viadal, undok marakodás tartott már közel egy óráig, a
midőn egy vén farkas csúnyául elkezdett üvölteni, rá, mintegy
jelszóra, visszaüvöltöttek a város minden részéből társai s azzal
egyszerre iramodott valahány, annyi felé.
Simon vitéz csakhamar kitalálta e futás okát, s visszament
testvéréhez és felkölté:
– Ébredj fel öcsém; lódobogást hallok, a tatárok jőnek vissza.
Nem volt más menekülés, mint mind a kettőnek lefeküdni a
halottak közé, arczczal földfelé fordulva s úgy várni csendesen a
közeledőket.
Épen ide jöttek az omladék templomba.
Sokszor tettek ők így. Gondolták, a menekült nép azt hiszi, hogy
nincs már mit keresnünk feldult városában s visszatért romjai közé,
üssünk rajta. Sokat elvesztettek így.
Azon városból való ember vezette őket vissza: egy tatárrá lett
lakos, ki maga is átpártolt az ellenséghez s előljárt, a hol pusztítni
kellett.
Ez az átkozott gonosz ember maga is tatár ruhát viselt már,
hosszu hegyes prémsüveget, bő nadrágot s törte a tatár szót a
kedvükért; – hogy az Isten fullaszsza a torkán, valahány kijön rajta!
A testvérek kivehették a beszédből, hogy az átpártolt rossz
ember azért vezette ide az ellenséget, hogy felfedezze előttük a
kripta nyilását, melybe az elfutott lakosság drágaságait, s templomi
ékszereit elrejtette, az ajtót befalaztatván utána. Azt ott felbontották
rögtön, s nagy lármával és dulakodással megosztoztak a talált
kincseken, összetörve, a mi nagyobb darab volt. A tatárrá lett
vezetőnek is jutott belőle egy szentségtartónak a fedele, mit a
gonosz ember süvege mellé tűzött czifraságnak.
– Hej, csak kerülnél egyszer a kezemre, gondolá magában Simon
vitéz, ki mindezt nézte félszemmel, a halottak között fekve.
Azután tüzet raktak a gyilkos tatárok a szent oltáron, a
templomban levágtak egy lovat, azt tiltul megsütötték nagy
konczokban s neki telepedtek lakmározni, hogy utálat volt őket látni;
az új tatár velük evett.
Egyszer egy parázs a tűzből kipattanva, épen Mikhál vitéz
kinyújtott markába esett; Simon vitéz látta azt jól, s megrettent,
hogyha öcscse az égető kínra meg talál mozdulni, mind a ketten
elvesznek. Mikhál vitéz azonban szép csendesen összeszorította a
markát, úgy hogy senki sem vette észre s olfojtotta benne az égő
parázst, még csak szisszenését sem lehetett hallani.
Hajnalra kelve aztán ismét felkerekedtek a tatárok, felkaptak
lovaik hátára s száguldottak odább; nem vették észre, hogy két élőt
hagytak el a holtak között.
A két vitéz késő estig átalla a templomból előjőni, hanem ott
viaskodott egyre a mezei vadakkal, a mikhez nappal még a keselyűk
is csatlakoztak, ott vijjongtak egész nap a fejük felett, csak hogy ki
nem verték a szemeiket karmaikkal. Hálát adtak az Istennek, a mint
a borzasztó helyről odább mehettek napnyugatkor.
A sík rónán mentek, a hogy mehettek sietve; hátra sem is igen
mertek nézni; de mit is néztek volna ottan egyebet, hanem ha a
sötét füstfelhőket, miket égő városokról hajtott feléjük a szél? Hátuk
mögött jött a tatár!
Estefelé egy magános tanyához értek, a melyben egy izmaelita
lakott. Duplán ellenség, mert idegen és pogány, hogy adott volna az
jó tanácsot a menekülőknek?
Sok mindenféle nép volt már akkor ott az udvarában, a kik
elfutottak a tatár elől s futottak, a merre világot láttak maguk előtt,
ki lovon, ki gyalog, ki szekéren, férfiak, asszonyok, gyermekek.
– Jaj édes feleim, ijesztgeté őket az izmaelita, rossz helyre
jöttetek ide: sokkal jobb volna visszafordulnotok, a merről a tatár
hadak jőnek, mert azok legalább, ha megadjátok magatokat, le nem
vágnak, csak rabszolgának visznek el; jaj de előlrül sokkal nagyobb
veszedelem vár reátok, mert itt ebben az erdőben laknak óriások,
rettentő magas szörnyek kétszarvú fejekkel, szájuk akkora, hogy egy
ember befér rajta; ezek elfogdossák az erdőkre futókat s ott
megsütik nyárson; engem is csak azért nem bántanak, mert bort
adok nekik, mikor jőnek.
Már ekkor a menekvők hallották Várad alól futó vitézektől a tatár
óriások hírét, kik egy egész sereget megszalasztottak puszta
feltünésük által, sőt egy csordapásztor, a ki becsületes jász eredetű
ember volt, maga is esküdött rá, hogy ő is látta őket, a mint négy
öles lépésekkel jártak végig a mezőn s egy közülök szépen leült a
kutágas tetejére, a nélkül, hogy a lábai lelógtak volna.
A szegény megrémült népség erre a hírre inkább visszafelé akart
futni a tatár torkába, hogysem e szörnyetegek fogaira jusson; de a
két Koppánd vitéz azt mondá okosan egymásnak:
Ime azok kevesebben vannak, a tatárok száma pedig sok
százezer. Az óriás húsa is csak hús: majd bejárja a kard, Goliáth is
óriás volt, s egy pásztor fiu ölte meg; inkább menjünk mi azok ellen.
S elindultak az erdő felé.
– No majd megbánjátok! kiálta utánuk az izmaelita.
Hát a mint a vitézek az erdőhöz közelértek, ime kijöve a fák közől
tizenkét rettentő alak; háromszorta magasabbak, mint a közönséges
ember; nagy fejük, mint holmi hordó; bajuszok, mint egész lófark;
három ölet léptek egyszerre, s két öles kardokat czepeltek a
vállaikon.
– No öcsém, szólt Simon vitéz, kardmarkolatához kapva, már
most vagy mi eszünk, vagy ők esznek; válaszd ki a magadét, én is az
enyimet.
S azzal kivont karddal rárohantak az óriásokra.
A szörnyű alakok eleinte nagyon lármáztak reájuk s kardjaikat
emelgették; a mint azonban látnák, hogy a két vitézt semmikép sem
lehet megijeszteni, hátat adának és hosszú lépésekkel iramodtak
vissza az erdő felé.
Nem voltak azok valami természettől alkotott szörnyek, hanem
csak a tatár khám szemfényvesztői, kik hosszú lábtókon tudtak járni
s felöltöztek Isten csodáinak, hogy a futó népeket visszariaszszák
gyilkosaik körmei közé; az izmaelita jól tudta azt, mert velük értett.
A mint Simon vitéz meglátta, hogy az óriások futnak, még jobban
biztatta testvérét ellenük, a holott azután nem érék be azzal, hogy az
erdőig megkergették őket, hanem a mint azok a fák és cserjék
között lábtóikkal nem tudtak boldogulni, sem a nehéz álarcz és
rémpóla miatt ügyesen mozogni, nehéz kardjaiknak sem vehették
hasznát, ott a vitéz ifjak mind valamennyit levágták irgalom nélkül s
a nagy festett szörny-fejeket feltűzték az erdő szélében karók
hegyére, hogy a futó népek bátorságot kapjanak, ha azokat
messziről meglátják. Az áruló izmaelita nevét azonban Simon vitéz
felirá kardmarkolatára.
Megint mentek odább napnyugat irányában, míg végre a Tisza
vizéhez értek, a hol egy révet találtak, mely előtt már akkor sok
ember várakozott, a kik mind a tatárok elől futottak. A vámot ottan
valami patarénus nép szedte, mert még András király és Dienes
nádor idejében mind ilyen huzavona nép kezébe kerültek a vámok.
Azt lehetne gondolni, hogy ilyen nagy veszedelem idején, mikor
mindenki tűz elől, vér közől fut tova, ingyen is átszállították a
révészek a menekülőket? Igen, keresztyén és magyar ember
bizonyára azt tette volna, de az istentelen patarénus nép most
sarczolta az átkelőket legjobban, ki mit megmentett a tatárok elől,
testén maradottat, azt oda kellett nekik adnia, asszonyok
fülönfüggőiket, férfiak bogláraikat vetették váltságul a
kegyetleneknek, csakhogy átszállítsák őket. A kiknek pedig épen
semmijök sem volt, a kik koldusképen futottak el, azokkal azt az
istentelenséget követték, hogy elébb elmondattak velük egy
manichæus imádságot, mely nem volt egyéb, mint a legirtóztatóbb
káromlása az igaz Istennek és az ő szenteinek tatár nyelven. Igen
sokan elmondták azt, csakhogy menekülhessenek, nem gondolván a
halál félelmében lelkük örök életére; a kik irtóztak elmondani a
csúfságot, másutt kerestek a Tiszán gázlót, vagy ha úszni tudtak,
ahoz fogtak, sokan ott is vesztek.
A két testvérnek sem volt semmije, a mivel megváltsa a révet,
csak az istenkáromló tatár imádság. Simon vitéz azt mondá, hogy
inkább darabokra engedi magát vágatni a tatár által, hogy sem az
Istent káromolja és a szent Szűzet, de Mikhál könnyebb vérű lévén,
azzal biztatá, majd elmondja ő azt mind a kettőjük helyett, azt
állítván, hogy testvére néma; ő tehát elmondá kétszer is egymás
után, egyszer magáért, másszor a bátyjáért a rettentő káromkodást,
mialatt Simon összetett kézzel magában halkan mondá utána a
Miatyánkot és az Üdvözletet. Így szállíták őket át a túlsó partra, a
holott a midőn Simon vitéz szemére vetné testvérének, hogy miért
mondta el kényszerűségből az istenkáromló verseket, ez azzal
vigasztalá bátyját, hogy hiszen magában minden vers végén utána
mondta: «nem igaz, nem igaz.» De csak mégis nagy bűn volt az.
Simon vitéz a manichæus nevét is feljegyzé kardmarkolatára.
Hajh de a menekülők ott csak újabb veszedelem torkába
futottak; a sajói nagy ütközet el volt már vesztve, a Duna Tisza
között is özönnel járt már a tatár, a mint egy erdő széléből kiértek,
köröskörül nem láttak egyebet a távol láthatáron, mint égő falvak
füstjét; visszatértek hát megint az erdőbe s felfelé északnak kezdtek
tartani, köröskörül hallva a tatárok kürtjeinek hangját, a mint
egymásnak felelgettek, s a nappalokat odvas fák rejtekeiben tölték,
nem találva egyéb táplálékot, mint vadmézet és lehullott
bükkmogyorót, a mivel éhségüket csillapíták.
Negyed napra találtak egy tisztességes házat az erdő közepén,
melyet sem lőrések, sem sánczkarók nem védelmezének s mégsem
volt leégetve.
Az ifju vitézek csodálkoztak ezen; pedig hát tudniok kellett volna,
hogy abban a házban szaraczenus lakik, a kik pedig mind
egyetértenek a tatárokkal, azok hordanak nekik tudósítást, vezetik
őket a városokra, kémeik és orgazdáik; a mit a tatár rabolt, azt
megveszik tőle olcsó pénzen s szállítják majdan Morvába és odább
is. Egy ilyen kufár háza volt az. Egy nagy vörös ökörfő volt a
kapujára festve, a miről a tatárok ráismerhettek, hogy ez az ő
emberük.
A szaraczenus nagy nyájassággal fogadta őket, mikor bementek
hozzá; biztatá, hogy várjanak, mindjárt készíttet számukra ebédet, a
mi a kiéhezett jámboroknak vajmi kedves vigasztalás volt. Míg ott
panaszolnák kiállott szenvedéseiket a jámbor arczú házi gazdának,
jön lihegve egy úri asszony, megszakgatott ruhájáról, feslett
sarujáról ki lehete venni, hogy messziről menekült futva s
reménykedve kérdi a házi gazdától, nem tért-e ide be az ő szerette
férje kis fiacskájával? Az erdőbe menekültek öten: a férj kis fiával, a
hitves, egy dajka és a kis csecsemő gyermek. Egyszer kutyaugatást
hallottak: a férj azt mondá, hogy hárman maradjanak hátra egy
barlangban elbujva, majd ő fiával előre megy, megnézni: nincs-e ott
emberi lak közel? ők sokáig vártak ott, végre a nő aggódva férje
kimaradtán, maga indult el őt keresni, talán itten voltak?
– Meglehet, hogy itt jártak, gyermecském, szólt vállat vonva a
szaraczén, itt sokan megfordulnak napjában; milyenek voltak?
A nő leirta férje alakját, ruházatát, a kis gyermekét, a fiucska
ujján volt egy fekete lószőr gyűrű fehér kereszttel, azt csak nem
vette el tőle senki, ha megölték is, ráismerhetne róla.
A szaraczén azt mondta, hogy semmikép sem látta őket s a
szegény nő kezét tördelve és jajongva ment ismét odább férjét és kis
fiát keresni.
Ez alatt felhozták az ifju vitézek számára az ételt, egy nagy
bográcsban aprított húst, a szaraczén hozatott nekik melléje bort s
megáldva lakomájukat, magukra hagyá őket.
Mikhál vitéz, a milyen éhes volt, rögtön hozzá akart fogni a
bőséges étkezéshez, de Simon vitéz megállítá elébb.
– Hát Mikhál, nem jut-e eszedbe, hogy elébb imádkoznánk?
Azzal elvégzék az imát, a hogy istenfélőkhöz illett, s csak akkor
fogának az étekhez.
És ime, Isten megjutalmazá őket kegyességűkért, mert a mint
Mikhál vitéz görbe evőkését beleszúrá a bográcsba, ime mi akadt
legelébb is kése hegyére, egy vékony csont, egy fekete
karikagyűrűvel lószőrből átkerítve, fehér kereszt a gyűrű közepén.
Az ifjak ijedten ugrának fel ültökből s nem érintve többé sem
ételt, sem italt, nem búcsúztak sem gazdától, sem gazdasszonytól,
hanem futottak onnan sebten, a hogy lábaik elbirták, s csak későn
akadtak meg egy szegény remete barlangja előtt, kinek elbeszélték
az ijedtséget, a mi velük történt.
Áldjátok Istent, fiaim, szólt az öreg aszketa, hogy megszabadíta a
gonosz barlangból, mert nem más lakik ottan, mint az istentelen
szaraczén, a tatárok kéme, ki a hozzá betérő menekülőknek kábító
szert ad italban s mikor elalusznak tőle, akkor fejüket veszi! a
fejekért kap egy dénárt a tatároktól, a húsaikat pedig feladja az
utánuk jövő vendégeknek, azt a szörnyűt követve el, hogy testvéreit
eteti meg a magyarral. Örüljetek, hogy nem izlelétek ott semmit, jól
fog esni most forrásom friss vize s az aszalt gyökerek, miket veletek
megosztok. Reggelig maradjatok itten, azután menjetek csak mindig
feljebb észak felé; nem tévedhettek el: a melyik oldalon a fáknak
moha van, arra van észak; ha hét napi járó földet tettetek hegyeken-
völgyeken keresztül, meglátjátok a legmagasabb hegyeket, a mik
Magyarország határán vannak; ottan majd hallani fogtok harangszót;
az vezessen benneteket; ott jó oltalom van, azok ott a «menedék
kövei», lapides refugii, miket a harczos szerzetek láttanak el védelmi
eszközökkel, hogy befogadják a mindenünnen futókat. Ott jó
helyetek leszen. Találtok oltárt, kenyeret, erős bástyákat, miket a jó
kard és a jó Isten ezernyi ellenségtől megoltalmaz. Míg odáig nem
értek, meg ne állapodjatok, mert veszedelem és pusztulás van az
egész hazán.
Az ifju vitézek megcsókolták a jó öreg kezét a jótékony tanácsért
s reggel útmutatása szerint mentek nagy egyedül magukban sűrű
erdőkön keresztül; soká mentek, messze mentek, tölgy elhagyta,
bükk elhagyta már a hegyet, következtek a nagy gyászoló fenyőfák,
de még tovább kellett menniök.
Egy reggel azonban, a nagy magános rengetegben, a mint
pihenni leülének, távolról jövő harangszó ütötte meg füleiket, valami
nagy harangok szava, a minők csak Fehérvárott voltak akkor, meg
Nagy-Váradon, a nagy székes egyházakban.
Mikhál vitéz felugrott örömmel és mondá:
– Itt van bizonyára az említett «lapis refugii».
De Simon bátyja megcsóválta fejét.
– Messzebb van az öcsém, még háromnapi járó földet mondott
odáig a szent ember.
– Ejh, talán saját lábaihoz mérte a járó földet, azok pedig már
öregek.
– Aztán nem is észak felől jön ez a hang, hanem nagyon is
nyugatról.
– Bizonyosan mi tévesztettük el az irányt.
Mikhál vitéz csak rábeszélte Simon bátyját, hogy ne menjenek
már messzebbre, hanem keressék fel, a honnan az a harangszó jön,
hiszen harangszóval csak keresztyén ember ad jelt; bizonyosan azért
teszik, hogy ha valaki eltévedt bujdosásában, odatérjen, a hol nem
félnek az ellenségtől.
Simon ráállt s mentek aztán, a honnan a harangszó jött, s a mint
kiértek az erdőből, egy kies völgy terült el előttük, melyen keskeny
patak kigyózott keresztül, a patakon nagy lábas hid volt verve, a hid
pedig egy magas sziklavárba vezetett fel, melynek négy hegyes
tornya volt a négy szegletén, ötödik meg a középen; azokban mind
harangok voltak s azokat mind úgy húzták, mintha búcsújárás volna.
Ez bizonyosan a menedék köve; mondá újból Mikhál vitéz.
– Nem mondott annak tornyairól, sem bástyáiról a remete; szólt
ellenkezve Simon bátyja.
– Ejh azóta felépíthették, hogy ő ott járt.
S azzal mentek a vár felé. De különös volt előttük, hogy az ilyen
nagy erős vár tövében a hogy másutt szokott lenni, nincsenek
paraszt kalibák, nincsen falu, zsellérházak, a kik a várhoz tartoznak,
hogy lehet ez?
– Bizonyosan a parasztokat mind bevették most a várba. Így
magyarázá azt a könnyebbvérű Mikhál lovag.
A toronyőr, a mint észrevette közeledésüket, rögtön jelt adott
kürtjével, mire a felvonó hidat leereszték, mely az állóhidat a
várkapuval összekötötte, czifra csatlósok jöttek a jövevények elé s
midőn azok aggodalmasan elmondák nekik, hogy ők messze földről
jőnek, országos veszedelem közől, nem tudják, jó helyre jöttek-e?
azok nevetve mondának nekik.
– Jó helyre bizony, atyafiak! ez itt Fulkó lovag vára; híres,
nevezetes vitézé; nem jöhet ide a tatár, ha csak a völgyet ki nem
tölti; nem is lesz itt fogyatkozástok semmiben, mert itt van enni inni
elég; van-e valami kincsetek, a mit el kell kell jó helyre tenni?
– Valóban nincs egyebünk jó kardjainkon kívül.
– No annál jobb. Akkor beállhattok a lovag úr zsoldjába s
vitézkedhettek az ő zászlói alatt jó pénzért.
– Nem kivánunk mi pénzt a szolgálatért, elég lesz nekünk, ha
harczolhatunk a pogány ellenség ellen vitéz vezetők alatt.
Az inasok úgy nevettek rajta, hogy az ifjak olyan komolyan
beszéltek s azután bevitték őket a várba s nemsokára hoztak eléjük
ezüst medenczékben illatos vizeket, megmosdatták, megfüröszték
őket, hoztak nekik pompás bársony és virágos kamuka-köntösöket,
arany skofiummal kivarrva, boglárokkal végig rakva, hajfürteiket
bekenték illatos kenőcsökkel; azt mondák, hogy ezt mind Fulkó lovag
parancsolta, a ki a vendégeit ilyen szívesen szokta fogadni.
– Talán nem is érdemeljük mi ezt a nagy tisztességet; monda
Simon lovag pironkodva, ki igen szemérmetes férfiu volt, midőn
ajándékokat kelle elfogadni.
– Ah de még többekben is fogtok részesülni, szóltak a tréfálózó
cselédek; a lovag úr lakomát rendezett számotokra, ottan lesznek az
úr-kisasszonyok is, Fulkó vitéz leányai, Meryza és Sziona, azok
mellett fogtok ülni.
– Oh de furcsa neveik vannak, mondá Simon lovag, vajjon hol
keresztelték őket annak?
– Ne törődjetek ti azzal; majd holnap elmondhatjátok, melyik volt
kettő közől a szebb?
Mikhál vitéznek mindjárt meg is ragadt a szívében: melyik lehet
kettő közől a szebb? mert a szép asszonyi arczokat ő halálba tudta
szeretni; de Simon bátyjának máson járt a gondolatja.
– Hol van itten a kápolna? oda szeretnék elébb menni, hálát adni
az Istennek, hogy annyi veszély közől megszabadított; sok hete,
hogy nem voltam már oltár előtt, csak az égi madarakkal együtt
imádhatám Istent az erdőkben napköltekor.
Az ínasok megint csak nevettek rajta.
– Hagyd azt mostan, jó barátom, megtalálhatod még holnap, a
papot mindig jókor van látni; most jertek a lakomára; régen
ülhettetek asztal mellett.
Simon vitéz nagyon csóválta rá fejét; nem tetszett neki az olyan
hely, a hol az oltárról olyan nevetve beszélnek, de nem akart
háboruságot kezdeni s engedett a meghívásnak, de öcscsét mégis
figyelmezteté, hogy a hosszas bőjtölés után, majd a gazdag
lakomából nehogy sokat be találjon venni, bort ne igen nagyon
igyék, mert az megárt most egyszerre; Mikhál vitéznek pedig máson
járt akkor az esze: melyik lesz szebb a kettő közől?
Egy trombitaszóra aztán felnyiltak a várbeli szárnyas ajtók s
bevezeték azokon az ifjakat az ebédlő-terembe.
A két jámbor vitéz szemefénye elveszett a nagy ragyogáson, a mi
itt minden oldalról feléjük tündökölt. Az asztalok ezüst tálakkal és
arany serlegekkel rakva, székek, lóczák czifrán kifestve és kifaragva,
ablakok színes üvegekkel rakva, az asztalfőn álló székek biborral
bevonva és mennyezettel födözve, mintha fejedelmek számára
állnának ottan; minden szék háta mögött állt egy arany vitézkötéses
hajdu, skárlát mentében, a bortöltögető ezüst vederrel kezében;
azután a másik terem ajtajai is felnyilván, kijöttek belőle a várkastély
úri vendégei, mind gazdagon öltözött urak, kiki egy-egy szép hölgyet
vezetve jobbján, a kik nehéz selyem ruháikkal csak úgy söpörték a
padlót, gyémánt és kárbunkulus tündökölt forgóikban, kösöntyűiken;
azok ott páronkint helyet foglaltak a hosszú rakott asztal körül, egy
férfi egy asszony mellett, végre hármas trombitaszó után jött maga a
vár ura: Fulkó; kövér termete majd leroskadt drágakövek és
boglárok terhe alatt; két kezén vezeté két leányát, Meryzát és
Szionát.
Az első, kit jobbján vezetett, tündéri szépségű hölgy volt,
ragyogó fekete szemei illettek halvány arczához s piros ajkaihoz,
magas, délczeg termete is oly méltósággal hordta e büszke főt,
mintha tudná, hogy itt neki mindenki engedelmes szolgája.
A másik leány, kit Fulkó balfelől bocsátott, alacsony volt és görbe-
hátú, szemeit nem is emelte fel soha, s nem tekintgetett sehová,
mint a ki nagyon jól tudja, hogy őt mindenki megveti. Könnyű volt
rámondani: melyik kettő közől a szebbik?
Mikhál vitéz azt hivé e látványra, hogy álmodik, szemeit elvakítá a
drágakövek fénye, még jobban a szép szemek ragyogása, hogy azt
sem tudta már: a földön jár-e vagy az égben?
Simon vitéz pedig ennyi pompát látva maga előtt, arra gondolt
szomorú szívében, vajjon talán ez időben Béla király futó patak
partján iszsza levett sisakjából a vértől langyult vizet?
– Asztalhoz, urak és hölgyek! hangzék Fulkó lovag szava; ide
mellém Koppánd Simon, Koppánd Mikhál; az utóbb jött vendégé
mindig az első hely nálam. Üljetek leányaim mellé. Im ez Meryza
leányom, amaz pediglen Sziona.
Mikhál úgy ejté a dolgot, hogy a tündéri szép Meryza mellé
jusson, kiről le nem birta szemeit venni többé. Simon pedig odaült a
szemlesütő Szionához, hanem elébb elmondá magában halkan az
asztal-áldást, a mi fölött a többi vendégek nagyon kaczagtak a
kegyes vitéz botránkoztatására, egy hang azonban mellette halkan
suttogá: «Amen, Amen.» Oda nézett s látta, hogy az a púpos hátú
Sziona, s e pillanatban szebbnek tetszett előtte a görbe leány, mint a
délczeg Meryza.
A vendég urak igen vígan ittak, nem kellett nekik nagy kinálkozás
s miután jól felborozták magukat, megkérték a jövevény ifjakat,
hogy mondják el előttük azon viszontagságokat, a miket idáig jutva
kiállottak.
Mikhál vitéz nem bírt nagy ékesen szólással, a miért is csak
bátyjának inte, hogy szóljon. Simon tehát felálla és gondolva, hogy
igaz résztvevő hazafiui szivekre talál e helyen, elkezdé a hon gyász-
eseményeit mondani előttük; a beszéd folytán mindjobban belejött
az indulatba, a lelke előtt újra megjelenő rémlátások képe ihletet
adott ajkainak, annyira, hogy végtére oly szívrehatólag beszélt, hogy
saját magának is könyek csorogtak alá az orczáján.
Ime azonban, midőn e könyeket letörölné és széttekintene, akkor
látá, hogy a vendégsereg épen nem sír és nem sóhajtoz az ő
fájdalmas beszédén, hanem csupán csak mulatságképen hallgatja
azt, mintha valami trufátor énekes regéjét hallgatná.
Ezen annyira megbotránkozott, hogy kénytelenül megszakasztá a
szót.
Különösen bántották őt a délczeg Meryza szép szemei, a miért
olyan mosolyogva tekintének reá.
Midőn elhallgatott, a délczeg hajadon megszólítá, hogy mondana
még «több ilyen szép mesét is».
Egy suttogó hang azonban, a halavány Sziona szava, esengve
szólt mellette, hogy ne folytassa tovább az Isten nevéért, mert hisz e
borzalmas történetet szívszakadás így hallani.
És Simon lovag Sziona szavára hallgatott, nagyot sóhajta és leült.
Sajnálta a házi urat és a vendég-sereget azzal megbántani, hogy
érzéketlenségüket megrója; gondolá, a jó élet teszi azt s azzal menté
ki magát, hogy nagyon el van már fáradva.
Arra fölkelt Saksin lovag, egy roppant termetes férfi Simon mellől
s belékötött, hogy miért nem iszik s mért nem beszél tovább? minek
sérti meg a társaságot azzal, hogy elhallgat; ezért már most «ki a
gyepre!»
Simon lovag látta, hogy ebből most mindjárt verekedés lesz,
azért hátratolta maga alul a székét s készen tartotta magát
mindenre. Nem volt ez szokatlan dolog akkoriban, midőn
vendégségek alatt nagyon sok bort ittak s a férfiui erő kitüntetése
nem tartatott gyalázatnak, a miért is lakoma előtt a vendégek
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