Effective Python 86 - 90

Click here for the first post, which contains the context of this series.

Item #86: Consider module-scoped code to configure deployment environments.

  • Programs often need to run in multiple deployment environments that each have unique assumptions and configurations.
  • You can tailor a module's contents to different deployment environments by using normal Python statements in module scope.
  • Module contents can be the product of any external condition, including host introspection through the sys and os modules.

Item #87: Define a root Exception to insulate callers from APIs.

  • Defining root exceptions for modules allows API consumers to insulate themselves from an API.
  • Catching root exceptions can help you find bugs in code that consumes an API.
  • Catching the Python Exception base class can help you find bugs in API implementations.
  • Intermediate root exceptions let you add more specific types of exceptions in the future without breaking your API consumers.

Item #88: Know how to break circular dependencies.

  • Circular dependencies happen when two modules must call into each other at import time. They can cause your program to crash at startup.
  • The best way to break a circular dependency is by refactoring mutual dependencies into a separate module at the bottom of the dependency tree.
  • Dynamic imports are the simplest solution for breaking a circular dependency between modules while minimizing refactoring and complexity.

Item #89: Consider warnings to refactor and migrate usage.

  • The warnings module can be used to notify callers of your API about deprecated usage. Warning messages encourage such callers to fix their code before later changes break their programs.
  • Raise warnings as errors by using the -W error command-line argument to the Python interpreter. This is especially useful in automated tests to catch potential regressions of dependencies.
  • In production, you can replicate warnings into the logging module to ensure that your existing error reporting systems will capture warnings at runtime.
  • It's useful to write tests for the warnings that your code generates to make sure that they'll be triggered at the right time in any of your downstream dependencies.

Item #90: Consider static analysis via typing to obviate bugs.

  • Python has special syntax and the typing built-in module for annotating variables, fields, functions, and methods with type information.
  • Static type checkers can leverage type information to help you avoid many common bugs that would otherwise happen at runtime.
  • There are a variety of best practices for adopting types in your programs, using them in APIs, and making sure they don't get in the way of your productivity.