Beyond the Basic Stuff with Python Best Practices for Writing Clean Code (Al Sweigart) (Z-Library)

Author: Al Sweigart

科学

BRIDGE THE GAP BETWEEN NOVICE AND PROFESSIONAL You’ve completed a basic Python programming tutorial or finished Al Sweigart’s best selling Automate the Boring Stuff with Python. What’s the next step toward becoming a capable, confident software developer? Welcome to Beyond the Basic Stuff with Python. More than a mere collection of advanced syntax and masterful tips for writing clean code, this book will teach you how to advance your Python programming skills by using the command line and other professional tools like code formatters, type checkers, linters, and version control. Sweigart takes you through best practices for setting up your development environment, naming variables, and improving readability, then tackles documentation, organization and performance measurement, as well as object-oriented design and the Big-O algorithm analysis commonly used in coding interviews. The skills you learn will boost your ability to program—not just in Python but in any language. You’ll learn: • Coding style, and how to use Python’s Black auto-formatting tool for cleaner code • Common sources of bugs, and how to detect them with static analyzers • How to structure the files in your code projects with the Cookiecutter template tool • Functional programming techniques like lambda and higher-order functions • How to profile the speed of your code with Python’s built-in timeit and cProfile modules • The computer science behind Big-O algorithm analysis • How to make your comments and docstrings informative, and how often to write them • How to create classes in object-oriented programming, and why they’re used to organize code Toward the end of the book you’ll read a detailed source-code breakdown of two classic command-line games, the Tower of Hanoi (a logic puzzle) and Four-in-a-Row (a two-player tile-dropping game), and a breakdown of how their code follows the book’s best practices. You’ll test your skills by implementing the program yourself. Of course, no single book can m

📄 File Format: PDF
💾 File Size: 7.6 MB
10
Views
0
Downloads
0.00
Total Donations

📄 Text Preview (First 20 pages)

ℹ️

Registered users can read the full content for free

Register as a Gaohf Library member to read the complete e-book online for free and enjoy a better reading experience.

📄 Page 1
A L S W E I G A R T B E Y O N D T H E B A S I C S T U F F W I T H P Y T H O N B E S T P R A C T I C E S F O R W R I T I N G C L E A N C O D E
📄 Page 2
BEYOND THE BASIC STUFF WITH PYTHON
📄 Page 3
(This page has no text content)
📄 Page 4
San Francisco B E YO N D T H E B A S I C S T U F F W I T H P Y T H O N B e s t P r a c t i c e s f o r W r i t i n g C l e a n C o d e Al Sweigar t
📄 Page 5
BEYOND THE BASIC STUFF WITH PYTHON. Copyright © 2021 by Al Sweigart.   All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher. ISBN-13: 978-1-59327-966-0 (print) ISBN-13: 978-1-59327-967-7 (ebook) Publisher: William Pollock Executive Editor: Barbara Yien Production Editor: Maureen Forys, Happenstance Type-O-Rama Developmental Editor: Frances Saux Cover Design: Octopod Studios Interior Design: Octopod Studios Cover Illustration: Josh Ellingson Technical Reviewer: Kenneth Love Copyeditor: Anne Marie Walker Compositor: Happenstance Type-O-Rama Proofreader: Rachel Monaghan Indexer: Valerie Perry For information on book distributors or translations, please contact No Starch Press, Inc. directly: No Starch Press, Inc. 245 8th Street, San Francisco, CA 94103 phone: 1-415-863-9900; info@nostarch.com www.nostarch.com Library of Congress Cataloging-in-Publication Data Library of Congress Cataloging-in-Publication Data Names: Sweigart, Al, author. Title: Beyond the basic stuff with python : best practices for writing clean code / Al Sweigart. Description: San Francisco, CA : No Starch Press, Inc., [2021] | Includes index. Identifiers: LCCN 2020034287 (print) | LCCN 2020034288 (ebook) | ISBN 9781593279660 (paperback) | ISBN 9781593279677 (ebook) Subjects: LCSH: Python (Computer program language) | Computer programming. Classification: LCC QA76.73.P98 S943 2021 (print) | LCC QA76.73.P98 (ebook) | DDC 005.13/3—dc23 LC record available at https://lccn.loc.gov/2020034287 LC ebook record available at https://lccn.loc.gov/2020034288 No Starch Press and the No Starch Press logo are registered trademarks of No Starch Press, Inc. Other product and company names mentioned herein may be the trademarks of their respective owners. Rather than use a trademark symbol with every occurrence of a trademarked name, we are using the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.
📄 Page 6
For my nephew Jack
📄 Page 7
(This page has no text content)
📄 Page 8
About the Author Al Sweigart is a software developer and tech book author living in Seattle. Python is his favorite programming language, and he is the developer of sev- eral open source modules for it. His other books are freely available under a Creative Commons license on his website at https://www.inventwithpython.com/. His cat Zophie weighs 11 pounds. About the Technical Reviewer Kenneth Love is a programmer, teacher, and conference organizer. He is a Django contributor and PSF Fellow, and currently works as a tech lead and software engineer for O’Reilly Media.
📄 Page 9
(This page has no text content)
📄 Page 10
B R I E F C O N T E N T S Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi PART I: GETTING STARTED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Chapter 1: Dealing with Errors and Asking for Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Chapter 2: Environment Setup and the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 PART II: BEST PRACTICES, TOOLS, AND TECHNIQUES . . . . . . . . 43 Chapter 3: Code Formatting with Black . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Chapter 4: Choosing Understandable Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 Chapter 5: Finding Code Smells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Chapter 6: Writing Pythonic Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Chapter 7: Programming Jargon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Chapter 8: Common Python Gotchas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Chapter 9: Esoteric Python Oddities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Chapter 10: Writing Effective Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Chapter 11: Comments, Docstrings, and Type Hints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 Chapter 12: Organizing Your Code Projects with Git . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 Chapter 13: Measuring Performance and Big O Algorithm Analysis . . . . . . . . . . . . . . . . 225 Chapter 14: Practice Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 PART III: OBJECT-ORIENTED PYTHON . . . . . . . . . . . . . . . . . . 273 Chapter 15: Object-Oriented Programming and Classes . . . . . . . . . . . . . . . . . . . . . . . . . 275 Chapter 16: Object-Oriented Programming and Inheritance . . . . . . . . . . . . . . . . . . . . . . 293 Chapter 17: Pythonic OOP: Properties and Dunder Methods . . . . . . . . . . . . . . . . . . . . . . 315 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi PART 1: GETTING STARTED . . . . . . . . . . . . . . . . . . . . . . 1 Chapter 1: Dealing with Errors and Asking for Help . . . . . . . . . . . . . . . . . . . . . 3 Chapter 2: Environment Setup and the Command Line . . . . . . . . . . . . . . . . . . 17 PART 2: BEST PRACTICES, TOOLS, AND TECHNIQUES . . 43 Chapter 3: Code Formatting with Black . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Chapter 4: Choosing Understandable Names . . . . . . . . . . . . . . . . . . . . . . . . 59 Chapter 5: Finding Code Smells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Chapter 6: Writing Pythonic Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Chapter 7: Programming Jargon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Chapter 8: Common Python Gotchas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Chapter 9: Esoteric Python Oddities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Chapter 10: Writing Effective Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Chapter 11: Comments, Docstrings, and Type Hints . . . . . . . . . . . . . . . . . . . 181 Chapter 12: Organizing Your Code Projects with Git . . . . . . . . . . . . . . . . . . 199 Chapter 13: Measuring Performance and Big O Algorithm Analysis . . . . . . . . 225 Chapter 14: Practice Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247 PART 3: OBJECT-ORIENTED PYTHON . . . . . . . . . . . . 273 Chapter 15: Object-Oriented Programming and Classes . . . . . . . . . . . . . . . . 275 Chapter 16: Object-Oriented Programming and Inheritance . . . . . . . . . . . . . 293 Chapter 17: Pythonic OOP: Properties and Dunder Methods . . . . . . . . . . . . . 315 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
📄 Page 11
(This page has no text content)
📄 Page 12
   xi C O N T E N T S I N D E T A I L ACKNOWLEDGMENTS xix INTRODUCTION xxi Who Should Read This Book and Why . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii About This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii Your Programming Journey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiv PART I: GETTING STARTED 1 1 DEALING WITH ERRORS AND ASKING FOR HELP 3 How to Understand Python Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Examining Tracebacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Searching for Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Preventing Errors with Linters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 How to Ask for Programming Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Limit Back and Forth by Providing Your Information Upfront . . . . . . . . . . . . . . 10 State Your Question in the Form of an Actual Question . . . . . . . . . . . . . . . . . 10 Ask Your Question on the Appropriate Website . . . . . . . . . . . . . . . . . . . . . . 10 Summarize Your Question in the Headline . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Explain What You Want the Code to Do . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Include the Full Error Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Share Your Complete Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Make Your Code Readable with Proper Formatting . . . . . . . . . . . . . . . . . . . . 12 Tell Your Helper What You’ve Already Tried . . . . . . . . . . . . . . . . . . . . . . . . . 13 Describe Your Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Examples of Asking a Question . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2 ENVIRONMENT SETUP AND THE COMMAND LINE 17 The Filesystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Paths in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 The Home Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 The Current Working Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Absolute vs . Relative Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Programs and Processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 The Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Opening a Terminal Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Running Programs from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Using Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Running Python Code from the Command Line with -c . . . . . . . . . . . . . . . . . . 26 Running Python Programs from the Command Line . . . . . . . . . . . . . . . . . . . . 26 C O N T E N T S I N D E T A I L About the Author . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii About the Technical Reviewer . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii ACKNOWLEDGMENTS XIX INTRODUCTION XXI Who Should Read This Book and Why . . . . . . . . . . . . . . . . . . . . . xxii About This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii Your Programming Journey . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xxiv PART 1 GETTING STARTED 1 1 DEALING WITH ERRORS AND ASKING FOR HELP 3 How to Understand Python Error Messages . . . . . . . . . . . . . . . . . . . 4 Examining Tracebacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Searching for Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Preventing Errors with Linters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 How to Ask for Programming Help . . . . . . . . . . . . . . . . . . . . . . . . . 9 Limit Back and Forth by Providing Your Information Upfront . . . . . . . 10 State Your Question in the Form of an Actual Question . . . . . . . . . . 10 Ask Your Question on the Appropriate Website . . . . . . . . . . . . . . . 10 Summarize Your Question in the Headline . . . . . . . . . . . . . . . . . . 11 Explain What You Want the Code to Do . . . . . . . . . . . . . . . . . . . . 11 Include the Full Error Message . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Share Your Complete Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Make Your Code Readable with Proper Formatting . . . . . . . . . . . . 12 Tell Your Helper What You’ve Already Tried . . . . . . . . . . . . . . . . . 13 Describe Your Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Examples of Asking a Question . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2 ENVIRONMENT SETUP AND THE COMMAND LINE 17 The Filesystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Paths in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 The Home Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 The Current Working Directory . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Absolute vs . Relative Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Programs and Processes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 The Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Opening a Terminal Window . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Running Programs from the Command Line . . . . . . . . . . . . . . . . . . 23 Using Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . . 24 Running Python Code from the Command Line with -c . . . . . . . . . . . 26 Running Python Programs from the Command Line . . . . . . . . . . . . . 26 Running the py .exe Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Running Commands from a Python Program . . . . . . . . . . . . . . . . . 27 Minimizing Typing with Tab Completion . . . . . . . . . . . . . . . . . . . . 27
📄 Page 13
xii   Contents in Detail Running the py .exe Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Running Commands from a Python Program . . . . . . . . . . . . . . . . . . . . . . . . . 27 Minimizing Typing with Tab Completion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Viewing the Command History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Working with Common Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Environment Variables and PATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Viewing Environment Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Working with the PATH Environment Variable . . . . . . . . . . . . . . . . . . . . . . . . 36 Changing the Command Line’s PATH Environment Variable . . . . . . . . . . . . . . 37 Permanently Adding Folders to PATH on Windows . . . . . . . . . . . . . . . . . . . . 38 Permanently Adding Folders to PATH on macOS and Linux . . . . . . . . . . . . . . . 39 Running Python Programs Without the Command Line . . . . . . . . . . . . . . . . . . . . . . . . 39 Running Python Programs on Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Running Python Programs on macOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Running Python Programs on Ubuntu Linux . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 PART III: BEST PRACTICES, TOOLS,  AND TECHNIQUES 43 3 CODE FORMATTING WITH BLACK 45 How to Lose Friends and Alienate Co-Workers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Style Guides and PEP 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 Horizontal Spacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Use Space Characters for Indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Spacing Within a Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Vertical Spacing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 A Vertical Spacing Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 Vertical Spacing Best Practices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Black: The Uncompromising Code Formatter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Installing Black . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Running Black from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Disabling Black for Parts of Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4 CHOOSING UNDERSTANDABLE NAMES 59 Casing Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 PEP 8’s Naming Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Appropriate Name Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Too Short Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Too Long Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Make Names Searchable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Avoid Jokes, Puns, and Cultural References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 Don’t Overwrite Built-in Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 The Worst Possible Variable Names Ever . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
📄 Page 14
Contents in Detail   xiii 5 FINDING CODE SMELLS 69 Duplicate Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Magic Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Commented-Out Code and Dead Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Print Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Variables with Numeric Suffixes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Classes That Should Just Be Functions or Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 List Comprehensions Within List Comprehensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 Empty except Blocks and Poor Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Code Smell Myths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Myth: Functions Should Have Only One return Statement at the End . . . . . . . . 80 Myth: Functions Should Have at Most One try Statement . . . . . . . . . . . . . . . . 81 Myth: Flag Arguments Are Bad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Myth: Global Variables Are Bad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 Myth: Comments Are Unnecessary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 6 WRITING PYTHONIC CODE 87 The Zen of Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 Learning to Love Significant Indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Commonly Misused Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Use enumerate() Instead of range() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Use the with Statement Instead of open() and close() . . . . . . . . . . . . . . . . . . . 93 Use is to Compare with None Instead of == . . . . . . . . . . . . . . . . . . . . . . . . . 94 Formatting Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 Use Raw Strings If Your String Has Many Backslashes . . . . . . . . . . . . . . . . . . 95 Format Strings with F-Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Making Shallow Copies of Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Pythonic Ways to Use Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Use get() and setdefault() with Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Use collections .defaultdict for Default Values . . . . . . . . . . . . . . . . . . . . . . . . . 99 Use Dictionaries Instead of a switch Statement . . . . . . . . . . . . . . . . . . . . . . 100 Conditional Expressions: Python’s “Ugly” Ternary Operator . . . . . . . . . . . . . . . . . . . . 101 Working with Variable Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 Chaining Assignment and Comparison Operators . . . . . . . . . . . . . . . . . . . . 103 Checking Whether a Variable Is One of Many Values . . . . . . . . . . . . . . . . . 103 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 7 PROGRAMMING JARGON 107 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 Python the Language and Python the Interpreter . . . . . . . . . . . . . . . . . . . . . 108 Garbage Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Objects, Values, Instances, and Identities . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
📄 Page 15
xiv   Contents in Detail Mutable and Immutable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 Indexes, Keys, and Hashes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Containers, Sequences, Mapping, and Set Types . . . . . . . . . . . . . . . . . . . . 119 Dunder Methods and Magic Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Modules and Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Callables and First-Class Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Commonly Confused Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Statements vs . Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Block vs . Clause vs . Body . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Variable vs . Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Function vs . Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Iterable vs . Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 Syntax vs . Runtime vs . Semantic Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Parameters vs . Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Type Coercion vs . Type Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Properties vs . Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Bytecode vs . Machine Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 Script vs . Program, Scripting Language vs . Programming Language . . . . . . . 129 Library vs . Framework vs . SDK vs . Engine vs . API . . . . . . . . . . . . . . . . . . . . 130 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Further Reading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 8 COMMON PYTHON GOTCHAS 133 Don’t Add or Delete Items from a List While Looping Over It . . . . . . . . . . . . . . . . . . . 134 Don’t Copy Mutable Values Without copy .copy() and copy .deepcopy() . . . . . . . . . . . . 140 Don’t Use Mutable Values for Default Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Don’t Build Strings with String Concatenation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Don’t Expect sort() to Sort Alphabetically . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Don’t Assume Floating-Point Numbers Are Perfectly Accurate . . . . . . . . . . . . . . . . . . . 147 Don’t Chain Inequality != Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 Don’t Forget the Comma in Single-Item Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 9 ESOTERIC PYTHON ODDITIES 153 Why 256 Is 256 but 257 Is Not 257 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 String Interning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155 Python’s Fake Increment and Decrement Operators . . . . . . . . . . . . . . . . . . . . . . . . . 156 All of Nothing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Boolean Values Are Integer Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 Chaining Multiple Kinds of Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 Python’s Antigravity Feature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 10 WRITING EFFECTIVE FUNCTIONS 161 Function Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Function Size Trade-Offs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
📄 Page 16
Contents in Detail   xv Function Parameters and Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Default Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Using * and ** to Pass Arguments to Functions . . . . . . . . . . . . . . . . . . . . . 166 Using * to Create Variadic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Using ** to Create Variadic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Using * and ** to Create Wrapper Functions . . . . . . . . . . . . . . . . . . . . . . 171 Functional Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Side Effects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Higher-Order Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Lambda Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Mapping and Filtering with List Comprehensions . . . . . . . . . . . . . . . . . . . . . 175 Return Values Should Always Have the Same Data Type . . . . . . . . . . . . . . . . . . . . . . 177 Raising Exceptions vs . Returning Error Codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179 11 COMMENTS, DOCSTRINGS, AND TYPE HINTS 181 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 Comment Style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Inline Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Explanatory Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184 Summary Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 “Lessons Learned” Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Legal Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 Professional Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 Codetags and TODO Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Magic Comments and Source File Encoding . . . . . . . . . . . . . . . . . . . . . . . . 187 Docstrings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 Type Hints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Using Static Analyzers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Setting Type Hints for Multiple Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Setting Type Hints for Lists, Dictionaries, and More . . . . . . . . . . . . . . . . . . . 195 Backporting Type Hints with Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 12 ORGANIZING YOUR CODE PROJECTS WITH GIT 199 Git Commits and Repos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Using Cookiecutter to Create New Python Projects . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Installing Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 Configuring Your Git Username and Email . . . . . . . . . . . . . . . . . . . . . . . . . 203 Installing GUI Git Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 The Git Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 How Git Keeps Track of File Status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 Why Stage Files? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 Creating a Git Repo on Your Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 Adding Files for Git to Track . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Ignoring Files in the Repo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209 Committing Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 Deleting Files from the Repo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Renaming and Moving Files in the Repo . . . . . . . . . . . . . . . . . . . . . . . . . . 215
📄 Page 17
xvi   Contents in Detail Viewing the Commit Log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Recovering Old Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Undoing Uncommitted Local Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Unstaging a Staged File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Rolling Back the Most Recent Commits . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Rolling Back to a Specific Commit for a Single File . . . . . . . . . . . . . . . . . . . 219 Rewriting the Commit History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 GitHub and the git push Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Pushing an Existing Repository to GitHub . . . . . . . . . . . . . . . . . . . . . . . . . . 222 Cloning a Repo from an Existing GitHub Repo . . . . . . . . . . . . . . . . . . . . . . 222 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223 13 MEASURING PERFORMANCE AND BIG O ALGORITHM ANALYSIS 225 The timeit Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 The cProfile Profiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228 Big O Algorithm Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 Big O Orders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 A Bookshelf Metaphor for Big O Orders . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Big O Measures the Worst-Case Scenario . . . . . . . . . . . . . . . . . . . . . . . . . 235 Determining the Big O Order of Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Why Lower Orders and Coefficients Don’t Matter . . . . . . . . . . . . . . . . . . . . 238 Big O Analysis Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 The Big O Order of Common Function Calls . . . . . . . . . . . . . . . . . . . . . . . . 242 Analyzing Big O at a Glance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Big O Doesn’t Matter When n Is Small, and n Is Usually Small . . . . . . . . . . . 244 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 14 PRACTICE PROJECTS 247 The Tower of Hanoi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 The Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 The Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250 Writing the Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 Four-in-a-Row . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 The Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259 The Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Writing the Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 PART III: OBJECT-ORIENTED PYTHON 273 15 OBJECT-ORIENTED PROGRAMMING AND CLASSES 275 Real-World Analogy: Filling Out a Form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 Creating Objects from Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
📄 Page 18
Contents in Detail   xvii Creating a Simple Class: WizCoin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Methods, __init__(), and self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 Private Attributes and Private Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 The type() Function and __qualname__ Attribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 Non-OOP vs . OOP Examples: Tic-Tac-Toe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 Designing Classes for the Real World Is Hard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 16 OBJECT-ORIENTED PROGRAMMING AND INHERITANCE 293 How Inheritance Works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 Overriding Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 The super() Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Favor Composition Over Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 Inheritance’s Downside . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301 The isinstance() and issubclass() Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Class Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 Class Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 Static Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 When to Use Class and Static Object-Oriented Features . . . . . . . . . . . . . . . . . . . . . . 307 Object-Oriented Buzzwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 When Not to Use Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 Multiple Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309 Method Resolution Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 17 PYTHONIC OOP: PROPERTIES AND DUNDER METHODS 315 Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 Turning an Attribute into a Property . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316 Using Setters to Validate Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 Read-Only Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 When to Use Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322 Python’s Dunder Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 322 String Representation Dunder Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 Numeric Dunder Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325 Reflected Numeric Dunder Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 In-Place Augmented Assignment Dunder Methods . . . . . . . . . . . . . . . . . . . . 330 Comparison Dunder Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337 INDEX 339
📄 Page 19
(This page has no text content)
📄 Page 20
A C K N O W L E D G M E N T S It’s misleading to have just my name on the cover. This book wouldn’t exist without the efforts of many people. I’d like to thank my publisher, Bill Pollock; and my editors, Frances Saux, Annie Choi, Meg Sneeringer, and Jan Cash. I’d like to also thank production editor Maureen Forys, copy editor Anne Marie Walker, and No Starch Press executive editor Barbara Yien. Thanks to Josh Ellingson for another great cover illustration. Thank you to my technical reviewer, Kenneth Love, and all the other great friends I’ve met in the Python community.
The above is a preview of the first 20 pages. Register to read the complete e-book.

💝 Support Author

0.00
Total Amount (¥)
0
Donation Count

Login to support the author

Login Now
Back to List