Day 15: Functools. Lambda. Partial. Callable.
Hi 👋 I am Hud, a postdoc for engineering data science at the AI Manufacturing Center in Laramie, Wyoming. My funding is running out (AaAaaA !), so while I am actively looking for a new job, instead of doing the 205th coding certificate to prove my worthiness — I thought I’d do design challenges and document how I spend my time upskilling so other engineers can do the same.
Nowadays, certificates are everywhere. Documenting small upskill projects that you can later show off is the best way to get recognition as a professional engineer.
This is day 15 of a 30-day design challenge. Follow along and let me know if you get stuck!
TL;DR tasks
Download the provided code for the challenge.
Task 1: Understand the code and its objectives
- Review the provided object-oriented weather service code and its functionality.
- Understand the goal of refactoring the code to make it functional and rely on higher-order functions.
Task 2: Convert the WeatherService class to functions
- Extract the logic from the WeatherService class and convert it into separate functions.
- Create a
get_forecast
function that takes anHttpClient
, a city, and an API key as arguments, and returns the forecast object. - Refactor the properties that retrieve temperature, humidity, etc., into separate functions that take the forecast object as an argument and extract the relevant information.
Task 3: Transform the RequestsClient class into a higher-order function
- Modify the
RequestsClient
class to be a singleget
function instead. - Convert the
get
function into a higher-order function by making it accept another function as an argument.
Task 4: Implement the higher-order function
- Modify the
get_forecast
function to accept the HTTP getter function as an argument. - Replace the calls to the
RequestsClient
class within theget_forecast
function with the provided HTTP getter function.
Task 5: Define a function with default arguments
- Create a new function that allows getting weather forecasts without providing the HTTP getter function and API key.
- Set default values for the HTTP getter function and the API key within this function.
Task 6: Test the functional code
- Verify that the refactored code functions correctly by running tests or using sample data.
- Ensure that the weather forecasts are retrieved successfully and the higher-order function is working as expected.
Task 7: Evaluate the benefits of functional code and higher-order functions
- Consider the advantages of using functional code and higher-order functions, such as improved readability, composability, and flexibility.
- Assess how the code has become more declarative and expressive through the use of higher-order functions.
Protocol is ok, can be better
We continue from our previous challenge where we’ve demonstrated the power of abstractions. There’s nothing really wrong with the code, I am just not quite happy and want to try shortening it. I mean, we have 4 class objects CityNotFoundError
, HttpClient
, RequestsClient
, WeatherApi
— Can we replace these classes with functions? How’d that look like? We sorta did that already here [REF], but this is an alternative — I want to emphasize and practice this bit to drill the concept deep in our brains.
Better: Higher order functions
Callable
to the rescue! Again (see challenge XX). The Callable
type hint is used to specify the type of a function or method that can be called with a specific set of arguments and return a specific type. In this case, HttpGet
is a type hint for a function that takes a single string argument and returns a value of any type.
When get_forecast
is called, the http_get
parameter can be passed any function that matches the HttpGet
signature, including the get
function defined in the same module or any other function that takes a string argument and returns a value of any type. This allows the behavior of get_forecast
to be customized by injecting a different function that retrieves the weather data from a different source or with different parameters.
Great! But how do we actually implement it?
Lambda and partial
Here’s two ways: lambda
and partial
.
The lambda
function is an anonymous function that takes a single argument city
and calls the get_forecast
function with three arguments: get
, API_KEY
, and city
. The get
argument is a function that retrieves data from a URL, and API_KEY
is a constant that contains the API key for the weather service. By using lambda
, we can create a new function that only requires the city
argument to work.
The partial
function is used to create a new function that is a partial application of the get_forecast
function. The first argument to partial
is the function to be partially applied, followed by any arguments that should be bound to that function. In this case, we are binding the get
and API_KEY
arguments to get_forecast
, which means that the resulting function only requires the city
argument to work.
The advantage of using lambda
is that it is concise and easy to read, especially for simple functions. However, it can become unwieldy for more complex functions, as it can be difficult to read and understand the code.
The advantage of using partial
is that it is more flexible and can be used to create more complex functions. It can also be easier to read and understand the code, as the function signature is more explicit. However, it can be more verbose and harder to read for simple functions.
In general, lambda
is a good choice for simple functions that only require a few arguments, while partial
is a better choice for more complex functions that require more arguments or have more complex logic.
Did you notice that we have (almost) no traditional class objects in the whole code? Generally that makes it shorter, less boilerplate, less overhead.
Conclusion
Congratulations! You finished Day 15 from the 30-day design challenge.
If you have reached this far, you know how to:
- Use higher order functions to replace bulky class objects
Check out the day 16 challenge!
Also, you can access the full 30-day GitHub repository here.
💡 My goal here is to help engineering data scientists upskill in design. I’d like to hear from you! Was this helpful? Anything I can improve? Connect with me on LinkedIn | Medium