Generic Data Structure: A Customizable Container
In Python, we often work with collections of data. While standard Python lists and dictionaries are versatile, sometimes you need a specialized container that enforces certain types of elements or has specific behavior. This challenge asks you to create a generic container class that can hold elements of a specified type, enhancing type safety and predictable behavior.
Problem Description
Your task is to implement a generic TypedContainer class in Python. This class should be able to store elements, but crucially, it should only allow elements of a specific, pre-defined type. When the container is initialized, you should specify the type of elements it will hold. Any attempt to add an element of a different type should raise a TypeError.
Key Requirements:
- Generic Type Specification: The
TypedContainershould accept a type hint during initialization (e.g.,int,str,list). - Element Addition: Implement a method (e.g.,
addorappend) to add elements to the container. This method must check if the type of the element being added matches the container's specified type. - Type Enforcement: If an element of an incorrect type is added, raise a
TypeErrorwith a descriptive message. - Element Retrieval: Provide a way to access the stored elements (e.g., by making the container iterable or providing a
get_allmethod). - Container Behavior: The container should behave like a list in terms of storing multiple elements in order.
Expected Behavior:
- A
TypedContainerinitialized forintshould only accept integers. - A
TypedContainerinitialized forstrshould only accept strings. - Attempts to add non-matching types should result in a
TypeError.
Edge Cases:
- What happens if you try to initialize the container with a non-type object? (e.g., an integer value instead of
int). This should ideally be handled, perhaps by raising aTypeErrororValueError. - Consider the case of
None. ShouldNonebe allowed if the specified type isOptional[SomeType]? For this challenge, assumeNoneis only allowed if the specified type isNoneTypeitself, or if it's explicitly allowed by a mechanism not covered here (i.e., focus on exact type matching for now).
Examples
Example 1:
# Initialize a container for integers
int_container = TypedContainer(int)
# Add valid integers
int_container.add(10)
int_container.add(25)
# Attempt to add a string
try:
int_container.add("hello")
except TypeError as e:
print(e)
# Retrieve elements
print(list(int_container))
Output:
Cannot add 'hello' (str) to a container expecting <class 'int'>.
[10, 25]
Explanation: The TypedContainer was initialized to hold int. When "hello" (a str) was added, a TypeError was raised. The valid integers were stored and can be retrieved.
Example 2:
# Initialize a container for strings
string_container = TypedContainer(str)
# Add valid strings
string_container.add("apple")
string_container.add("banana")
# Attempt to add a float
try:
string_container.add(3.14)
except TypeError as e:
print(e)
# Retrieve elements
print(list(string_container))
Output:
Cannot add 3.14 (<class 'float'>) to a container expecting <class 'str'>.
['apple', 'banana']
Explanation: Similar to Example 1, but for strings. A float was rejected.
Example 3: Initialization Error
# Attempt to initialize with a non-type value
try:
invalid_container = TypedContainer(123)
except TypeError as e:
print(e)
Output:
Expected a type for the container, but received <class 'int'>.
Explanation: The constructor expects a type object (like int or str), not an instance of a type. This input caused a TypeError during initialization.
Constraints
- The
TypedContainerclass must be implemented using standard Python features. - The element storage should maintain insertion order, similar to a list.
- The
addmethod should have a time complexity of O(1) on average (excluding the type check, which is typically O(1)). - The
TypedContainershould be iterable.
Notes
- Consider using
isinstance()for type checking. - The
__init__method is where you should store the expected type. - The
addmethod is where the core type enforcement logic will reside. - Making your class iterable (e.g., by implementing
__iter__) is a good way to allow easy retrieval of elements. - Think about how you can provide a clear and informative error message when a type mismatch occurs.