Log In
Or create an account ->
Imperial Library
Home
About
News
Upload
Forum
Help
Login/SignUp
Index
Clean Code in Python
Title Page
Copyright and Credits
Clean Code in Python
Dedication
Packt Upsell
Why subscribe?
PacktPub.com
Contributors
About the author
About the reviewer
Packt is searching for authors like you
Table of Contents
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
Introduction, Code Formatting, and Tools
The meaning of clean code
The importance of having clean code
The role of code formatting in clean code
Adhering to a coding style guide on your project
Docstrings and annotations
Docstrings
Annotations 
Do annotations replace docstrings?
Configuring the tools for enforcing basic quality gates
Type hinting with Mypy
Checking the code with Pylint
Setup for automatic checks
Summary
Pythonic Code
Indexes and slices 
Creating your own sequences
Context managers
Implementing context managers
Properties, attributes, and different types of methods for objects
Underscores in Python
Properties
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
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
Handle exceptions at the right level of abstraction
Do not expose tracebacks
Avoid empty except blocks
Include the original exception
Using assertions in Python
Separation of concerns
Cohesion and coupling
Acronyms to live by
DRY/OAOO
YAGNI
KIS
EAFP/LBYL
Composition and inheritance
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
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
Single responsibility principle
A class with too many responsibilities
Distributing responsibilities
The open/closed principle
Example of maintainability perils for not following the open/closed principle
Refactoring the events system for extensibility
Extending the events system
Final thoughts about the OCP
Liskov's substitution principle
Detecting LSP issues with tools
Detecting incorrect datatypes in method signatures with Mypy
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
Summary
References
Using Decorators to Improve Our Code
What are decorators in Python?
Decorate functions
Decorate classes
Other types of decorator
Passing arguments to decorators
Decorators with nested functions
Decorator objects
Good uses for decorators
Transforming 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
The DRY principle with decorators
Decorators and separation of concerns
Analyzing 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
__get__(self, instance, owner)
__set__(self, instance, value)
__delete__(self, instance)
__set_name__(self, owner, name)
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 global shared state
Accessing the dictionary of the object
Using weak references
More considerations about descriptors
Reusing code
Avoiding class decorators
Analysis of descriptors
How Python uses descriptors internally
Functions and methods
Built-in decorators for methods
Slots
Implementing descriptors in decorators
Summary
References
Using Generators
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
Repeated iterations
Nested loops
The iterator pattern in Python
The interface for iteration
Sequence objects as iterables
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
The simplest use of yield from
Capturing the value returned by a sub-generator
Sending and receiving data to and from a sub-generator
Asynchronous programming
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
Frameworks and tools for testing
Frameworks and libraries for unit testing
unittest
Parametrized tests
pytest
Basic test cases with pytest
Parametrized tests
Fixtures
Code coverage
Setting up rest coverage
Caveats of test coverage
Mock objects
A fair warning about patching and mocks
Using mock objects
Types of mocks
A use case for test doubles
Refactoring
Evolving our code
Production code isn't the only thing that evolves
More about unit testing
Property-based testing
Mutation testing
A brief introduction to test-driven development
Summary
References
Common Design Patterns
Considerations for design patterns in Python
Design patterns in action
Creational patterns
Factories
Singleton and shared state (monostate)
Shared state
The borg pattern
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
Names in our models
Summary
References
Clean Architecture
From clean code to clean architecture
Separation of concerns
Abstractions
Software components
Packages
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
Leave a review - let other readers know what you think
← Prev
Back
Next →
← Prev
Back
Next →