Tackle inefficiencies and errors the Pythonic way

Key Features

  • Enhance your coding skills using the new features introduced in Python 3.9
  • Implement the refactoring techniques and SOLID principles in Python
  • Apply microservices to your legacy systems by implementing practical techniques

Book Description

Experienced professionals in every field face several instances of disorganization, poor readability, and testability due to unstructured code.

With updated code and revised content aligned to the new features of Python 3.9, this second edition of Clean Code in Python will provide you with all the tools you need to overcome these obstacles and manage your projects successfully.

The book begins by describing the basic elements of writing clean code and how it plays a key role in Python programming. You will learn about writing efficient and readable code using the Python standard library and best practices for software design.

The book discusses object-oriented programming in Python and shows you how to use objects with descriptors and generators. It will also show you the design principles of software testing and how to resolve problems by implementing software design patterns in your code. In the concluding chapter, we break down a monolithic application into a microservices-based one starting from the code as the basis for a solid platform.

By the end of this clean code book, you will be proficient in applying industry-approved coding practices to design clean, sustainable, and readable real-world Python code.

What you will learn

  • Set up a productive development environment by leveraging automatic tools
  • Leverage the magic methods in Python to write better code, abstracting complexity away and encapsulating details
  • Create advanced object-oriented designs using unique features of Python, such as descriptors
  • Eliminate duplicated code by creating powerful abstractions using software engineering principles of object-oriented design
  • Create Python-specific solutions using decorators and descriptors
  • Refactor code effectively with the help of unit tests
  • Build the foundations for solid architecture with a clean code base as its cornerstone

Who this book is for

This book is designed to benefit new as well as experienced programmers. It will appeal to team leads, software architects and senior software engineers who would like to write Pythonic code to save on costs and improve efficiency. The book assumes that you have a strong understanding of programming

Table of Contents

  1. Preface
    1. Who this book is for?
    2. What this book covers
    3. To get the most out of this book
    4. Download the example code files
    5. Download the color images
    6. Conventions used
    7. Get in touch
    8. Reviews
  2. Introduction, Code Formatting, and Tools
    1. Introduction
    2. The meaning of clean code
    3. The importance of having clean code
    4. Some exceptions
    5. Code formatting
    6. Adhering to a coding style guide on your project
    7. Documentation
    8. Code comments
    9. Docstrings
    10. Annotations
    11. Do annotations replace docstrings?
    12. Tooling
    13. Checking type consistency
    14. Generic validations in code
    15. Automatic formatting
    16. Setup for automatic checks
    17. Summary
    18. References
  3. Pythonic Code
    1. Indexes and slices
    2. Creating your own sequences
    3. Context managers
    4. Implementing context managers
    5. Comprehensions and assignment expressions
    6. Properties, attributes, and different types of methods for objects
    7. Underscores in Python
    8. Properties
    9. Creating classes with a more compact syntax
    10. Iterable objects
    11. Creating iterable objects
    12. Creating sequences
    13. Container objects
    14. Dynamic attributes for objects
    15. Callable objects
    16. Summary of magic methods
    17. Caveats in Python
    18. Mutable default arguments
    19. Extending built-in types
    20. A brief introduction to asynchronous code
    21. Summary
    22. References
  4. General Traits of Good Code
    1. Design by contract
    2. Preconditions
    3. Postconditions
    4. Pythonic contracts
    5. Design by contract – conclusions
    6. Defensive programming
    7. Error handling
    8. Value substitution
    9. Exception handling
    10. Using assertions in Python
    11. Separation of concerns
    12. Cohesion and coupling
    13. Acronyms to live by
    14. DRY/OAOO
    15. YAGNI
    16. KIS
    17. EAFP/LBYL
    18. Inheritance in Python
    19. When inheritance is a good decision
    20. Anti-patterns for inheritance
    21. Multiple inheritance in Python
    22. Method Resolution Order (MRO)
    23. Mixins
    24. Arguments in functions and methods
    25. How function arguments work in Python
    26. How arguments are copied to functions
    27. Variable number of arguments
    28. Positional-only parameters
    29. Keyword-only arguments
    30. The number of arguments in functions
    31. Function arguments and coupling
    32. Compact function signatures that take too many arguments
    33. Final remarks on good practices for software design
    34. Orthogonality in software
    35. Structuring the code
    36. Summary
    37. References
  5. The SOLID Principles
    1. The single responsibility principle
    2. A class with too many responsibilities
    3. Distributing responsibilities
    4. The open/closed principle
    5. Example of maintainability perils for not following the OCP
    6. Refactoring the events system for extensibility
    7. Extending the events system
    8. Final thoughts about the OCP
    9. Liskov's substitution principle
    10. Detecting LSP issues with tools
    11. Using mypy to detect incorrect method signatures
    12. Detecting incompatible signatures with pylint
    13. More subtle cases of LSP violations
    14. Remarks on the LSP
    15. Interface segregation
    16. An interface that provides too much
    17. The smaller the interface, the better
    18. How small should an interface be?
    19. Dependency inversion
    20. A case of rigid dependencies
    21. Inverting the dependencies
    22. Dependency injection
    23. Summary
    24. References
  6. Using Decorators to Improve Our Code
    1. What are decorators in Python?
    2. Function decorators
    3. Decorators for classes
    4. Other types of decorator
    5. More advanced decorators
    6. Passing arguments to decorators
    7. Decorators with nested functions
    8. Decorator objects
    9. Decorators with default values
    10. Decorators for coroutines
    11. Extended syntax for decorators
    12. Good uses for decorators
    13. Adapting function signatures
    14. Validating parameters
    15. Tracing code
    16. Effective decorators – avoiding common mistakes
    17. Preserving data about the original wrapped object
    18. Dealing with side effects in decorators
    19. Incorrect handling of side effects in a decorator
    20. Requiring decorators with side effects
    21. Creating decorators that will always work
    22. Decorators and clean code
    23. Composition over inheritance
    24. The DRY principle with decorators
    25. Decorators and separation of concerns
    26. Analysis of good decorators
    27. Summary
    28. References
  7. Getting More Out of Our Objects with Descriptors
    1. A first look at descriptors
    2. The machinery behind descriptors
    3. Exploring each method of the descriptor protocol
    4. The get method
    5. The set method
    6. The delete method
    7. The set name method
    8. Types of descriptors
    9. Non-data descriptors
    10. Data descriptors
    11. Descriptors in action
    12. An application of descriptors
    13. A first attempt without using descriptors
    14. The idiomatic implementation
    15. Different forms of implementing descriptors
    16. The issue of shared state
    17. Accessing the dictionary of the object
    18. Using weak references
    19. More considerations about descriptors
    20. Reusing code
    21. An alternative to class decorators
    22. Analysis of descriptors
    23. How Python uses descriptors internally
    24. Functions and methods
    25. Built-in decorators for methods
    26. Slots
    27. Implementing descriptors in decorators
    28. Final remarks about descriptors
    29. Interface of descriptors
    30. Object-oriented design of the descriptors
    31. Type annotations on descriptors
    32. Summary
    33. References
  8. Generators, Iterators, and Asynchronous Programming
    1. Technical requirements
    2. Creating generators
    3. A first look at generators
    4. Generator expressions
    5. Iterating idiomatically
    6. Idioms for iteration
    7. The next() function
    8. Using a generator
    9. Itertools
    10. Simplifying code through iterators
    11. The iterator pattern in Python
    12. Coroutines
    13. The methods of the generator interface
    14. close()
    15. throw(ex_type[, ex_value[, ex_traceback]])
    16. send(value)
    17. More advanced coroutines
    18. Returning values in coroutines
    19. Delegating into smaller coroutines – the 'yield from' syntax
    20. Asynchronous programming
    21. Magic asynchronous methods
    22. Asynchronous context managers
    23. Other magic methods
    24. Asynchronous iteration
    25. Asynchronous generators
    26. Summary
    27. References
  9. Unit Testing and Refactoring
    1. Design principles and unit testing
    2. A note about other forms of automated testing
    3. Unit testing and agile software development
    4. Unit testing and software design
    5. Defining the boundaries of what to test
    6. Tools for testing
    7. Frameworks and libraries for unit testing
    8. unittest
    9. pytest
    10. Code coverage
    11. Mock objects
    12. Refactoring
    13. Evolving our code
    14. Production code isn't the only one that evolves
    15. More about testing
    16. Property-based testing
    17. Mutation testing
    18. Common themes in testing
    19. Boundaries or limit values
    20. Classes of equivalence
    21. Edge cases
    22. A brief introduction to test-driven development
    23. Summary
    24. References
  10. Common Design Patterns
    1. Design pattern considerations in Python
    2. Design patterns in action
    3. Creational patterns
    4. Factories
    5. Singleton and shared state (monostate)
    6. Builder
    7. Structural patterns
    8. Adapter
    9. Composite
    10. Decorator
    11. Facade
    12. Behavioral patterns
    13. Chain of responsibility
    14. The template method
    15. Command
    16. State
    17. The null object pattern
    18. Final thoughts about design patterns
    19. The influence of patterns over the design
    20. Design patterns as theory
    21. Names in our models
    22. Summary
    23. References
  11. Clean Architecture
    1. From clean code to clean architecture
    2. Separation of concerns
    3. Monolithic applications and microservices
    4. Abstractions
    5. Software components
    6. Packages
    7. Managing dependencies
    8. Other considerations when managing dependencies
    9. Artifact versions
    10. Docker containers
    11. Use case
    12. The code
    13. Domain models
    14. Calling from the application
    15. Adapters
    16. The services
    17. Analysis
    18. The dependency flow
    19. Limitations
    20. Testability
    21. Intention revealing
    22. Summary
    23. References
    24. Summing it all up
  12. Other Books You May Enjoy
  13. Index