Mastering Object oriented Python Free ebook download

  Mastering Object-oriented Python

Grasp the intricacies of object-oriented programming

in Python in order to efficiently build powerful real-world applications Steven F. Lott

  BIRMINGHAM - MUMBAI

  Mastering Object-oriented Python

  Copyright © 2014 Packt Publishing All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews. Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book. Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information. First published: April 2014 Production Reference: 1150414 Published by Packt Publishing Ltd.

  Livery Place

  35 Livery Street Birmingham B3 2PB, UK

  ISBN 978-1-78328-097-1

  www.packtpub.com [email protected]

  Cover Image by Duraid Fatouhi ( )

  

Credits

Author

  Steven F. Lott Reviewers

  Mike Driscoll Róman Joost Sakis Kasampalis Albert Lukaszewski, Ph.D Hugo Solis

  Commissioning Editor Usha Iyer

  Acquisition Editor Gregory Wild

  Content Development Editor Shaon Basu

  Technical Editors Kapil Hemnani Monica John Akashdeep Kundu

  Copy Editors Insiya Morbiwala Kirti Pai Stuti Srivastava

  Project Coordinator Akash Poojary

  Proofreaders Stephen Copestake Clyde Jenkins Linda Morris Jonathan Todd

  Indexer Mariammal Chettiyar

  Graphics Abhinash Sahu

  Production Coordinator Alwin Roy

  Cover Work Alwin Roy About the Author

Steven F. Lott has been programming since the 70s, when computers were large,

  expensive, and rare. As a contract software developer and architect, he has worked on hundreds of projects from very small to very large. He's been using Python to solve business problems for over 10 years. Steven is currently a technomad who lives in various places on the east coast of the

  

  US. His technology blog is: I owe deep gratitude to Floating Leaf for all her support and guidance.

  About the Reviewers Mike Driscoll has been programming in Python since 2006. He enjoys writing

   . He has co-authored Core Python refcard for DZone. Mike has also been a technical reviewer for various books of Packt Publishing, such as Python 3 Object Oriented Programming,

  

Python 2.6 Graphics Cookbook , and Tkinter GUI Application Development Hotshot. Mike

recently wrote the book Python 101.

  I would like to thank my beautiful wife, Evangeline, for always supporting me. I would also like to thank my friends and family for all that they do to help me. I would also like to thank Jesus Christ for saving me.

  Róman Joost first learned about open source software in 1997. He is the project

  manager of GIMP's user documentation. He has contributed to GIMP and Python/ Zope open source projects for eight years. Róman works for Red Hat in Brisbane, Australia.

  Sakis Kasampalis is based in the Netherlands, where he currently works as a

  Software Engineer for a location-based B2B provider. He is not dogmatic about particular programming languages and tools; his principle is that the right tool should be used for the right job. One of his favorite tools is Python because he finds it very productive.

  Among the FOSS activities of Kasampalis is maintaining a GitHub repository that is

  

  related to implementing design patterns in Python, which are available at

  

Learning Python Design Patterns , Packt Publishing.

  

Albert Lukaszewski, Ph.D , is principal consultant for Lukaszewski Consulting

  Services in southeast Scotland. Having programmed computers for over 30 years, he consults on the system design and implementation. Previously, he served as Chief Engineer for ACCESS Europe GmbH. Much of his experience is related to text processing, database systems, and Natural Language Processing (NLP). In addition to MySQL for Python, Packt Publishing, he previously wrote a column on Python for

  About.com the New York Times subsidiary, .

  Hugo Solis

  is an assistant professor in the Physics department at the University of Costa Rica. His current research interests are computational cosmology, complexity, and the influence of hydrogen on material properties. He has wide experience with languages including C/C++ and Python for scientific programming and visualization. He is a member of the Free Software Foundation and has contributed code to some free software projects. Currently, he is in charge of the IFT, a Costa Rican scientific, non-profit organization for the multidisciplinary practice of physics

   ).

  I'd like to thank Katty Sanchez, my beloved mother, for her support and vanguard thoughts.

   Support files, eBooks, discount offers and more

  You might want to visit to your book. Did you know that Packt offers eBook versions of every book published, with PDF

   and as a print book customer, you are entitled to a discount on the eBook copy.

   for more details. , you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks. TM

  

  Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book library. Here, you can access, read and search across Packt's entire library of books.

  Why Subscribe?

  • Fully searchable across every book published by Packt • Copy and paste, print and bookmark content
  • On demand and accessible via web browser

  Free Access for Packt account holders

   PacktLib today and view nine entirely free books. Simply use your login credentials for immediate access.

  Table of Contents

  

  

  

  

  

  

  

  

  

  

  

   Part 1: Pythonic Classes via Special Methods

Chapter 1: The __init__() Method

  

  

  

  

  

  

  

  

  

  

  

  

  

  Table of Contents [

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

Chapter 2: Integrating Seamlessly with Python – Basic Special Methods

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

]

  

  

  Table of Contents

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  Chapter 4:

  

  

  

  

  

  

[ ]

  Table of Contents [ ]

  

  

  

  

  

  

  

Chapter 6:

  

  

Chapter 5:

  

  

  

  

  

  

  

  

  Table of Contents [

  

  

  

  

  

  

  

  

  

Chapter 8:

  

  

  

]

  

  

  

  

  

  

  Chapter 7:

  

  

  

  Table of Contents [ ]

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

Part 2: Persistence and Serialization

Chapter 9:

  

  

  Table of Contents [ ]

  

  

  

  

  

  

  

  

  

  

  

  

  

Chapter 11: Storing and Retrieving Objects via SQLite 327 SQL databases, persistence, and objects 328 The SQL data model – rows and tables 329 CRUD processing via SQL DML statements 331 Querying rows with the SQL SELECT statement 333 SQL transactions and the ACID properties 335 Designing primary and foreign database keys 337 Processing application data with SQL 339 Implementing class-like processing in pure SQL 340 Mapping Python objects to SQLite BLOB columns 342 Mapping Python objects to database rows manually 344 Designing an access layer for SQLite 346 Implementing container relationships 349

  Table of Contents [ ]

  

  

  

  

  

Chapter 12: Transmitting and Sharing Objects 367 Class, state, and representation

  

  

  

  

  

  

  

  

  

  

  Table of Contents [ ]

  

  

  

  

  

  

  

  

  

  

  

Part 3: Testing, Debugging, Deploying, and Maintaining

  

  

  

  

  Table of Contents [

  

  

  

  

  

  

  

  

  

  

]

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  Table of Contents [ ]

  

  

  

  

  

  

  

  

Chapter 17: The Module and Package Design 539 Designing a module

  Table of Contents

  

Chapter 18: Quality and Documentation 561 Writing docstrings for the help() function 561 Using pydoc for documentation

  

  

  

  

  

  

  

  

  

  

  

[ ]

  Preface

  This book will introduce you to more advanced features of the Python programming language. The focus is on creating the highest quality Python programs possible. This often means creating programs that have the highest performance or are the most maintainable. This means exploring design alternatives and determining which design offers the best performance while still being a good fit with the problem that is being solved.

  Most of the book will look at a number of alternatives for a given design. Some will have better performance. Some will seem simpler or be a better solution for the problem domain. It's essential to locate the best algorithms and optimal data structures to create the most value with the least computer processing. Time is money, and programs that save time will create more value for their users. Python makes a number of internal features directly available to our application programs. This means that our programs can be very tightly integrated with existing Python features. We can leverage numerous Python features by ensuring that our OO designs integrate well.

  We'll often focus on a specific problem and examine several variant solutions to the problem. As we look at different algorithms and data structures, we'll see different memory and performance alternatives. It's an important OO design skill to work through alternate solutions in order to properly optimize the final application.

  One of the more important themes of this book is that there's no single best approach to any problem. There are a number of alternative approaches with different attributes.

  Preface [

  • Some Preliminaries, covers some preliminary topics, such as unittest, doctest, docstrings, and some special method names.
  • Chapter 1, The _init_() Method, provides us with a detailed description and implementation of the
  • >Chapter 2, Integrating Seamlessly with Python – Basic Special Methods, will explain in detail as to how we can expand a simple class definition to add special methods. We'll need to take a look at the default behavior inherited from the object so that we can understand what overrides are needed and when they're actually needed.
  • Chapter 3, Attribute Access, Properties, and Descriptors, shows us how the default processing works in some detail. We need to decide where and when to override the default behavior. We will also explore descriptors and gain a much deeper understanding on how Python's internals work.
  • Chapter 4, The ABCs of Consistent Design, looks at the abstract base classes in the collections.abc module in general. We'll look at the general concepts behind the various containers and collections that we might want to revise or extend. Similarly, we'll look at the concepts behind the numbers that we might want to implement.

  

]

On programming style, the subject of style generates a surprising amount of interest.

  The astute reader will note that the examples do not meticulously conform to PEP-8 in every single particular detail of the name choice or punctuation. As we move towards achieving mastery over object-oriented Python, we'll spend a great deal of time reading Python code from a variety of sources. We'll observe wide variability even within the Python Standard Library modules. Rather than presenting examples that are all perfectly consistent, we've opted for some inconsistency, the lack of consistency will better confirm with code as seen in the various open source projects encountered in the wild.

  What this book covers

  We'll cover three advanced Python topics in a series of chapters that dig into the details.

  Part 1 , Pythonic Classes via Special Methods: This part looks more deeply at object-

  oriented programming techniques and how we can more tightly integrate the class definitions of our applications with Python's built-in features. It consists of nine chapters, which are as follows:

  _init_()

  method. We will look at different forms of initialization for simple objects. From this, we can look into more complex objects that involve collections and containers.

  Preface

  • Chapter 5, Using Callables and Contexts, looks at several ways to create context

  

contextlib

  managers using the tools in . We'll show you a number of variant designs for callable objects. This will show you why a stateful callable object is sometimes more useful than a simple function. We'll also take a look at how to use some of the existing Python context managers before we dive in and write our own context manager.

  • Chapter 6, Creating Containers and Collections, focuses on the basics of container classes. We'll review the variety of special methods that are involved in being a container and offering the various features that containers offer. We'll address extending built-in containers to add features. We'll also look at wrapping built-in containers and delegating methods through the wrapper to the underlying container.
  • Chapter 7, Creating Numbers, covers these essential arithmetic operators: , +

  / // %

  , , , , , and . We'll also take a look at these comparison operators:

  • < , > , <= , >= , == , and != . We'll finish by summarizing some of the design

    considerations that go into extending or creating new numbers.
    • Chapter 8, Decorators and Mixins – Cross-cutting Aspects, covers simple function decorators, function decorators with arguments, class decorators, and method decorators.

  

Part 2 , Persistence and Serialization: A persistent object has been serialized to a storage

  medium. Perhaps it's transformed to JSON and written to the filesystem. An ORM layer can store the object in a database. This part will take a look at the alternatives to handle persistence. This section contains five chapters, which are as follows:

  • Chapter 9, Serializing and Saving – JSON, YAML, Pickle, CSV, and XML, covers simple persistence using libraries focused on various data representations such as JSON, YAML, pickle, XML, and CSV.
  • Chapter 10, Storing and Retrieving Objects via Shelve, explains basic database

  shelve dbm operations with Python modules, such as (and ).

  • Chapter 11, Storing and Retrieving Objects via SQLite, moves to the more complex world of SQL and the relational database. Because SQL features don't match object-oriented programming features well, we have an

  impedance mismatch

  problem. A common solution is to use ORM to allow us to persist a large domain of objects.

  • Chapter 12, Transmitting and Sharing Objects, takes a look at the HTTP protocol, JSON, YAML, and XML representation to transmit an object.
  • Chapter 13, Configuration Files and Persistence, covers various ways in which a Python application can work with a configuration file.

  

[ ]

  Preface

  Part 3 , Testing, Debugging, Deploying, and Maintaining: We'll show you how to

  gather data to support and debug high-performance programs. This will include information on creating the best possible documentation in order to reduce the confusion and complexity of the support. This section contains the final five chapters, which are as follows:

  • Chapter 14, The Logging and Warning Modules, takes a look at using the

  logging warning and modules to create audit information, as well as debug.

  We'll take a significant step beyond using the print() function.

  • Chapter 15, Designing for Testability, covers designing for testability and how

  unittest doctest we use and .

  • Chapter 16, Coping with the Command Line, takes a look at using the argparse module to parse options and arguments. We'll take this a step further and use the command design pattern to create program components that can be combined and expanded without resorting to writing shell scripts.
  • Chapter 17, The Module and Package Design, covers module and package design. This is a higher-level set of considerations. We will take a look at related classes in a module and related modules in a package.
  • Chapter 18, Quality and Documentation, covers how we can document our design to create trust that our software is correct and has been properly implemented.

  What you need for this book

  In order to compile and run the examples mentioned in this book, you require the following software:

  • Python Version 3.2 or higher with the standard suite of libraries. We'll focus on Python 3.3, but the differences from 3.2 are minor.
  • We'll take a look at some additional packages. These include PyYaml, SQLAlchemy, and Jinja2.

  ° http://pyyaml.org °

  . When building this, check the installation guide,

   --without-cextensions

  . Using the option can simplify installation. °

  http://jinja.pocoo.org/

[ ]

  Preface

  • Optionally, you might want to add Sphinx or Docutils to your environment, as we'll cover them as well.

  ° http://sphinx-doc.org ° http://docutils.sourceforge.net

  Who this book is for

  This is advanced Python. You'll need to be quite familiar with Python 3. You'll also benefit from having fairly large or complex problems to solve. If you are a skilled programmer with the other languages, you may find this book helpful if you want to switch to Python. This book doesn't introduce syntax or other foundational concepts. Advanced Python 2 programmers may find this helpful when they switch to Python

  3. We won't cover any of the conversion utilities (such as from Version 2 to 3) or any of the coexistence libraries (such as six.) This book is focused on new development that has happened entirely in Python 3.

  Conventions

  In this book, you will find a number of styles of text that distinguish between different kinds of information. Here are some examples of these styles, and an explanation of their meaning. Code words in text are shown as follows: "We can access other Python modules through the use of the import statement." A block of code is set as follows:

  class Friend(Contact): def __init__(self, name, email, phone): self.name = name self.email = email self.phone = phone

  When we wish to draw your attention to a particular part of a code block, the relevant lines or items are set in bold:

  class Friend(Contact): def __init__(self, name, email, phone): self.name = name self.email = email self.phone = phone

  

[ ]

  Preface

  Any command-line input or output is written as follows:

  >>> e = EmailableContact("John Smith", "[email protected]") >>> Contact.all_contacts New terms

  and important words are shown in bold. Words that you see on the screen, in menus or dialog boxes for example, appear in the text like this: "We use this feature to update the label to a new random value every time we click on the

  Roll! button".

  Warnings or important notes appear in a box like this.

  Tips and tricks appear like this.

  Reader feedback

  Feedback from our readers is always welcome. Let us know what you think about this book—what you liked or may have disliked. Reader feedback is important for us to develop titles that you really get the most out of.

  [email protected]

  To send us general feedback, simply send an e-mail to , and mention the book title via the subject of your message. If there is a book that you need and would like to see us publish, please send us a note in the SUGGEST A TITLE form on www.packtpub.com or e-mail

  [email protected] .

  If there is a topic that you have expertise in and you are interested in either writing

  www.packtpub.com/authors or contributing to a book, see our author guide on .

  Customer support

  Now that you are the proud owner of a Packt book, we have a number of things to help you get the most from your purchase.

  

[ ]

  Preface Downloading the example code for this book

  You can download the example code files for all Packt books you have purchased

  http://www.PacktPub.com

  from your account at . If you purchased this book elsewhere, you can visit http://www.PacktPub. com/support and register to have the files e-mailed directly to you.

  Errata

  Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in the text or the code—we would be grateful if you would report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions

  

   entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded on our website, or added to any list of existing errata, under the Errata section of that title. Any existing errata can be viewed by selecting your title from http://www.packtpub.com/support .

  Piracy Piracy of copyright material on the Internet is an ongoing problem across all media.

  At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works, in any form, on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.

  [email protected]

  Please contact us at with a link to the suspected pirated material. We appreciate your help in protecting our authors, and our ability to bring you valuable content.

  Questions

  You can contact us at [email protected] if you are having a problem with any aspect of the book, and we will do our best to address it.

  

[ ]

  Some Preliminaries

  To make the design issues in the rest of the book clearer, we need to look at some of our motivational problems. One of these is the game of Blackjack. Specifically, we're interested in simulating strategies for playing Blackjack. We don't want to endorse gambling. Indeed, a bit of study will show that the game is stacked heavily against the player. This should reveal that most casino gambling is little more than a tax on the innumerate.

  Simulation, however, was one of the early problem domains for object-oriented programming. This is an area where object-oriented programming works

  

  An Introduction to Programming in Simula by Rob Pooley. This chapter will provide some background in tools that are essential for writing complete Python programs and packages. We'll use these tools in later chapters. We'll make use of the timeit module to compare various object-oriented designs to see which has better performance. It's important to weigh objective evidence along with the more subjective consideration of how well the code seems to reflect the problem domain.

  We'll look at the object-oriented use of the unittest and doctest modules. These are essential ingredients in writing software that are known to actually work. A good object-oriented design should be clear and understandable. In order to assure that it is understood and used as well as maintained properly, writing Pythonic documentation is essential. Docstrings in modules, classes, and methods are very important. We'll touch on RST markup here and cover it in depth in Chapter 18,

  Quality and Documentation .

  Apart from this, we'll address the Integrated Development Environment (IDE) question. A common question regards the best IDE for Python development.

  Some Preliminaries

  Finally, we'll introduce the concepts behind Python's special method names. The subject of special methods fills the first seven chapters. Here, we'll provide some background that may be of help in understanding Part 1, Pythonic Classes via Special Methods .

  We will try to avoid digressing into the foundations of Python object-oriented programming. We're assuming that you've already read the Python 3 Object Oriented

  

Programming book by Packt Publishing. We don't want to repeat things that have been

thoroughly stated elsewhere. In this book, we will focus solely on Python 3.

  We'll refer to a number of common, object-oriented design patterns. We'll try to avoid repeating the presentation in Packt's Learning Python Design Patterns.

  About casino Blackjack If you're unfamiliar with the casino game of Blackjack, here's an overview.

  The objective is to accept cards from the dealer to create a hand that has a point total that is between the dealer's total and 21. The number cards (2 to 10) have point values equal to the number. The face cards (jack, queen, and king) are worth 10 points. The ace is worth either 11 points or one point. When using an ace as 11 points, the value of the hand is soft. When using an ace as one point, the value is hard. A hand with an ace and seven, therefore, has a hard total of 8 and a soft total of 18. There are four two-card combinations that total twenty-one. These are all called even though only one of the four combinations involves a jack.

  blackjack Playing the game

  The game of Blackjack can vary from casino to casino, but the outline is similar. The mechanics of play work as follows:

  • First, the player and dealer each get two cards. The player, of course, knows the value of both of their cards. They're dealt face up in a casino.
  • One of the dealer's cards is face up and the other is face down. The player therefore knows a little bit about the dealer's hand, but not everything.
  • If the dealer has an ace showing, there's a 4:13 chance that the hidden card is worth 10 and the dealer has 21. The player can elect to make an additional insurance bet.

  

[ ]

  Some Preliminaries • Next, the player can elect to either receive cards or stop receiving cards.

  These two most common choices are called hit or stand.

  • There are some additional choices too. If the player's cards match, the hand can be split. This is an additional bet, and the two hands are played separately.
  • Finally, the players can double their bet before taking one last card. This is called doubling down. If the player's cards total 10 or 11, this is a common bet to make.

  The final evaluation of the hand works as follows:

  • If the player went over 21, the hand is a bust, the player loses, and the dealer's facedown card is irrelevant.
  • If the player's total is 21 or under, then the dealer takes cards according to a simple, fixed rule. The dealer must hit a hand that totals less than 18. The dealer must stand on a hand that totals 18 or more. There are some small variations here that we can ignore for the moment.
  • If the dealer goes bust, the player wins.
  • If both the dealer and player are 21 or under, the hands are compared to see if the player has won or lost.

  The amounts of the final payoffs aren't too relevant for now. For a more accurate simulation of various play and betting strategies, the payoffs will matter quite a bit.

  Blackjack player strategies

  In the case of Blackjack (which is different from a game such as Roulette), there are actually two kinds of strategies that the player must use, as follows:

  • A strategy to decide what game play to make: take insurance, hit, stand, split, or double down.
  • A strategy to decide what amount to bet. A common statistical fallacy leads players to raise and lower their bets in an attempt to preserve their winnings and minimize their losses. Any software to emulate casino games must also emulate these more complex betting strategies. These are interesting algorithms that are often stateful and lead to the learning of some advanced Python programming techniques.

  These two sets of strategies are the prime examples of the STRATEGY design pattern.

  

[ ]

  Some Preliminaries Object design for simulating Blackjack

  We'll use elements of the game like the player hand and card as examples of object modeling. However, we won't design the entire simulation. We'll focus on elements of this game because they have some nuance but aren't terribly complex. We have a simple container: one hand object will contain zero or more card objects.

  Card NumberCard FaceCard Ace We'll take a look at the subclasses of for , , and .

  We'll take a look at a wide variety of ways to define this simple class hierarchy. Because the hierarchy is so small (and simple), we can easily try a number of implementation alternatives.

  We'll take a look at a variety of ways to implement the player's hand. This is a simple collection of cards with some additional features. We also need to look at the player as a whole. A player will have a sequence of hands as well as a betting strategy and a Blackjack play strategy. This is a rather complex composite object. We'll also take a quick look at the deck of cards that cards are shuffled and dealt from.

  Performance – the timeit module timeit

  We'll make use of the module to compare the actual performance of different object-oriented designs and Python constructs. The timeit module contains a

  timeit

  number of functions. The one we'll focus on is named . This function creates

  Timer

  a object for some statement. It can also include some setup code that prepares the environment. It then calls the timeit() method of Timer to execute the setup just once and the target statement repeatedly. The return value is the time required to run the statement.

  The default count is 100,000. This provides a meaningful time that averages out other OS-level activity on the computer that is performing the measurement. For complex or long-running statements, a lower count may be prudent.

  timeit

  The following is a simple interaction with :

  >>> timeit.timeit( "obj.method()", """ ... class SomeClass: ... def method(self): ... pass ... obj= SomeClass() """) 0.1980541350058047

  

[ ]

  Some Preliminaries Downloading the example code You can download the example code files for all Packt Publishing books you have purchased from your account at

you can visit http://www.packtpub.com/support and

register to have the files e-mailed directly to you.

  The statement obj.method() is provided to timeit() as a string. The setup is the class definition and is provided as a string as well. It's important to note that everything required by the statement must be in the setup. This includes all imports as well as all variable definitions and object creation. Everything.

  It can take a few tries to get the setup complete. When using interactive Python, we often lose track of global variables and imports that have scrolled off the top of the terminal window. This example showed that 100,000 method calls that do nothing take 0.198 seconds.

  The following is another example of using timeit :

  >>> timeit.timeit( "f()",""" ... def f(): ... pass ... """ ) 0.13721893899491988

  This shows us that a do-nothing function call is slightly less expensive than a do- nothing method invocation. The overhead in this case is almost 44 percent. In some cases, OS overheads may be a measurable component of the performance. These tend to vary based on factors that are hard to control. We can use the

  repeat() timeit()

  function instead of the function in this module. It will collect multiple samples of the basic timing to allow further analysis of OS effects on performance. For our purposes, the timeit() function will provide all the feedback we need to measure the various object-oriented design considerations objectively.

  Testing – unittest and doctest

  Unit testing is absolutely essential. If there's no automated test to show a particular element functionality, then the feature doesn't really exist. Put another way, it's not done until there's a test that shows that it's done.

  

[ ]

  Some Preliminaries

  We'll touch, tangentially, on testing. If we were to delve into testing each object- oriented design feature, the book would be twice as big as it is. Omitting the details of testing has the disadvantage that it makes good unit tests seem optional. They're emphatically not optional.

  Unit testing is essential When in doubt, design the tests first. Fit the code to the test cases.

  Python offers two built-in testing frameworks. Most applications and libraries will make use of both. The general wrapper for all testing is the unittest module. In addition, many public API docstrings will have examples that can be found and used

  

doctest unittest doctest

by the module. Also, can incorporate modules of .

  One lofty ideal is that every class and function has at least a unit test. More importantly, visible classes, functions, and modules will have doctest too. There are other lofty ideals: 100 percent code coverage, 100 percent logic path coverage, and so on. Pragmatically, some classes don't need testing. A class created by namedtuple() ,

  namedtuple()

  for example, doesn't really need a unit test, unless you don't trust the implementation in the first place. If you don't trust your Python implementation, you can't really write applications with it. Generally, we want to develop the test cases first and then write code that fits these test cases. The test cases formalize the API for the code. This book will reveal numerous ways to write code that has the same interface. This is important. Once we've defined an interface, there are still numerous candidate implementations that fit the interface.

  One set of tests should apply to several different object-oriented designs.

  unittest

  One general approach to using the tools is to create at least three parallel directories for your project as follows:

  lib/

  • myproject

  : This directory is the final package that will be installed in

  

site-packages for your package or application. It has an __init__.py

package, and we'll put our files in here for each module.

  • test

  : This directory has the test scripts. In some cases, the scripts will parallel the modules. In some cases, the scripts may be larger and more complex than the modules themselves.

  • doc

  : This directory has other documentation. We'll touch on this in the next section as well as in Chapter 18, Quality and Documentation.

  

[ ]

  Some Preliminaries [ ]

  subclasses that will exercise three different kinds of objects:

  The third is an instance of

  types.SimpleNamespace .

  method. Each method builds a different kind of object for testing. One is an instance of an otherwise empty class. The second is an instance of

  setUp()

  classes each provide the required

  TestAccess

  The subclasses of the

  class SomeClass: pass class Test_EmptyClass( TestAccess ): def setUp( self ): self.object= SomeClass() class Test_Namespace( TestAccess ): def setUp( self ): self.object= types.SimpleNamespace() class Test_Object( TestAccess ): def setUp( self ): self.object= object()

  TestAccess

  In some cases, we'll want to run the same test suite on multiple candidate classes so that we can be sure that each candidate works. There's no point in doing

  , but no definition is provided, making this TestCase subclass abstract. A setUp() method is required by each concrete subclass. The following are three concrete

  self.object

  subclass defines a few tests that we're expecting a class to pass. The actual object being tested is omitted. It's referenced as

  TestCase

  This abstract

  import types import unittest class TestAccess( unittest.TestCase ): def test_should_add_and_get_attribute( self ): self.object.new_attribute= True self.assertTrue( self.object.new_attribute ) def test_should_fail_on_missing( self ): self.assertRaises( AttributeError, lambda: self.object. undefined )

  As part of object-oriented design, we'll often create technology spike modules that look like the code shown in this section. We'll break it down into three sections. First, we have the overall abstract test as follows:

  Unit testing and technology spikes

  timeit comparisons on code that doesn't actually work.

  object .

  Some Preliminaries

  In order to run these tests, we'll need to build a suite that doesn't allow us to run the

  TestAccess abstract test.

  The following is the rest of the spike:

  def suite(): s= unittest.TestSuite() s.addTests( unittest.defaultTestLoader.loadTestsFromTestCase(Test_ EmptyClass) ) s.addTests( unittest.defaultTestLoader.loadTestsFromTestCase(Test_ Namespace) ) s.addTests( unittest.defaultTestLoader.loadTestsFromTestCase(Test_ Object) ) return s if __name__ == "__main__": t= unittest.TextTestRunner() t.run( suite() )

  We now have concrete evidence that the object class can't be used the same way

  types.SimpleNamespace