Key Points
Introduction
- This workshop will cover a variety of intermediate Python topics that are commonly encountered in programming but may not be covered in beginner courses.
Virtual Environments
- Setting up a virtual environment is useful for managing project dependencies.
- Using
uvsimplifies the process of creating and managing virtual environments. - There are several options other than
uvfor managing virtual environments, such asvenvandconda. - It’s important to version control your project from the start,
including a
.gitignorefile.
Python Bits and Bobs
Iterables and Generators
- An iterable is any Python object that implements the
__iter__()method, which returns an iterator. - Iterators also implement the
__next__()method, which returns the next item in the sequence when called. - A generator is a special type of iterable that allows you to generate values on the fly, rather than storing them all in memory at once.
- Sets are unordered collections of unique elements that support mathematical set operations like union, intersection, difference, and symmetric difference.
Collections & Iterables
- The
collectionsmodule provides useful functions and objects for working with data more efficiently, such asCounter,deque, anddefaultdict. - The
itertoolsmodule provides useful functions for working with iterables, such ascombinations,permutations,chain, andcycle.
The Logging Module
- The
loggingmodule is useful for tracking the behavior of our program. - Using logging levels makes it easy to filter important messages from less important ones.
- Custom logging formats can provide more context and make logs easier to understand.
Decorators & Caching
- The
functoolsmodule provides useful tools for working with functions, such ascache,lru_cache,singledispatch, andwraps. - Caching can speed up repeated function calls by storing results in memory, but it can also consume memory if not used carefully.
- The
singledispatchdecorator allows us to define different behaviors for a function based on the type of its input. - The
wrapsdecorator helps preserve the original function’s metadata when creating decorators.
Creating A Module
- Python modules are simply directories with an
__init__.pyfile in them - You can add the path to your module directory to
sys.pathto make it available for import - You can use dot notation in your imports to specify the module, file, and function you want to use
Class Objects
- Python classes are defined using the
classkeyword, followed by the class name and a colon. - The
__init__method is a special method that is called when an instance of the class is created. - Class methods are defined like normal functions, but they must
include
selfas the first parameter.
More On Class Objects
- Dunder methods are special methods that start and end with double underscores.
- Static properties and methods are defined on the class itself, rather than on instances of the class.
- We can use the
@propertydecorator to define properties that can be accessed like attributes. - We can use the
@classmethoddecorator to define methods that operate on the class itself, rather than on instances of the class. - We can use the
@staticmethoddecorator to define methods that don’t operate on either the class or instances of the class, but are still related to the class in some way.
Extending Classes with Inheritance
- Inheritance allows us to create a new class that is a specialized version of an existing class
- We can override methods and properties in a subclass to provide specialized behavior
Unit Testing
- We can use
pytestto write and run unit tests in Python. - A good test is isolated, repeatable, fast, and clear.
- We can use fixtures to provide data or state to our tests.
- We can use monkey patching to modify the behavior of functions or classes during testing.
- Test Driven Development (TDD) is a practice where we write tests before writing the code to make the tests pass.
Inheritance and Composition
- Composition allows us to build complex functionality by combining several smaller, simpler classes
- Composition promotes separation of concerns, reusability, flexibility, and maintainability
- By using abstract base classes, we can define interfaces that subclasses must implement, allowing for flexibility in our code design
Static Code Analysis
- There are many static code analysis tools available for Python, each with its own strengths and weaknesses.
- Ruff is a fast linter and code formatter that can replace several
other tools, including
flake8,pylint, andisort. - MyPy is a static type checker that can help catch type-related errors in Python code.
Building and Deploying a Package
- We can build our package locally using
uv build, which creates adist/directory with the built package files. - We can use GitHub Actions to automate the building and deployment of our package.
- GitHub Actions workflows are defined using YAML files in the
.github/workflows/directory. - We can trigger our workflow to run on specific events, such as pushing a tag that follows semantic versioning.
- We can add additional steps to our workflow, such as running tests and static code analysis, to ensure code quality before deployment.
Multiprocessing
- Multiprocessing allows us to run multiple processes concurrently, which can improve performance for CPU-bound tasks.