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