Implement composition and mixin utilities
Point72Data Scientist · Online AssessmentLast updated
This problem tests proficiency in functional composition, Python metaclass/decorator patterns, and custom serialization logic, focusing on handling flexible arguments and object introspection.
Problem Statement
You are building a data transformation pipeline. You need to implement two distinct utilities: a function composer and a JSON-serializable mixin.
1. Function Composer
Implement a function compose_pipeline(*funcs) that returns a new function. This returned function should accept an arbitrary number of arguments and keyword arguments, pass them to the first function in the chain, and pass the result as the sole positional argument to each subsequent function. If the input list is empty, return the identity function.
2. Serializable Mixin
Create a class JsonMixin that enables any class inheriting from it to be serialized to a JSON string.
- Implement a method
to_json(self, include_private=False). - It should return a JSON string of all instance attributes.
- If
include_privateisFalse, exclude any attributes starting with an underscore_. - If the object contains non-serializable data (e.g., a function object or a custom class instance), catch the error and return a string literal: "[Unserializable]".
Examples
# Pipeline example
def add_five(x): return x + 5
def square(x): return x * x
pipeline = compose_pipeline(add_five, square)
print(pipeline(2)) # (2+5)^2 = 49
# Mixin example
class Data(JsonMixin):
def __init__(self, val, secret):
self.val = val
self._secret = secret
d = Data(10, "hidden")
print(d.to_json(include_private=False)) # '{"val": 10}'
Constraints
- The pipeline must handle variable arguments for the first function only.
- Use
json.dumpsfor the final serialization step. - Handle potential circular references gracefully if possible, or at least ensure the process does not crash indefinitely.
Hints
Hint 1
For the composer, use `*args` and `**kwargs` for the initial call, and then loop through the remaining functions using the result of the previous call.
Hint 2
For the mixin, use `vars(self)` or `self.__dict__` to inspect object attributes at runtime.
Hint 3
When handling non-serializable data in JSON, consider using a custom `default` parameter in `json.dumps` to replace non-serializable objects with the required string.
Follow-up questions
- How would you modify the pipeline to support asynchronous functions if some transformations involve I/O?
- If the object contains nested objects that also inherit from JsonMixin, how can you ensure the entire tree is serialized correctly?
- What are the performance trade-offs of using `getattr` or `__dict__` versus using a data class or Pydantic for serialization?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.