Implementing a Simplified Namedtuple in Python
Namedtuples are a powerful feature in Python's collections module, providing a way to create lightweight, immutable classes. This challenge asks you to implement a simplified version of namedtuple to understand its underlying principles. You'll be building a class that allows you to access attributes by name, similar to a regular class, but with the benefits of tuple immutability and memory efficiency.
Problem Description
You are tasked with creating a class called SimpleNamedTuple that mimics the core functionality of Python's namedtuple. This class should take a type string (e.g., "Point") and a list of field names as input during initialization. Instances of this class should behave like tuples, meaning they are immutable and can be indexed numerically. However, they should also allow access to attributes by their names (specified in the field names list).
Key Requirements:
- Initialization: The class constructor (
__init__) should accept a type string and a list of field names. - Attribute Access: Instances should allow access to attributes using both numerical indexing (e.g.,
instance[0]) and named attribute access (e.g.,instance.field_name). - Immutability: Instances should be immutable; attempting to modify an attribute after creation should raise an
AttributeError. - Tuple-like Behavior: Instances should behave like tuples in terms of length and iteration.
- String Representation: Instances should have a user-friendly string representation, similar to Python's built-in tuple.
Expected Behavior:
- Creating an instance with field names
['x', 'y']should allow access to attributes asinstance.x,instance.y,instance[0], andinstance[1]. - Attempting to assign a new value to an attribute (e.g.,
instance.x = 5) should raise anAttributeError. - The
len()function should return the number of fields. - Iterating over the instance (e.g.,
for value in instance: ...) should yield the values in the order they were provided during initialization.
Edge Cases to Consider:
- Empty field names list: Handle this gracefully (e.g., create an empty namedtuple).
- Invalid field names (e.g., names starting with a number or containing spaces): While not strictly required, consider how you might handle these. For simplicity, you can assume field names are valid.
Examples
Example 1:
Input:
type_name = "Point"
fields = ["x", "y"]
point = SimpleNamedTuple(type_name, fields, 10, 20)
Output:
point.x # Output: 10
point[1] # Output: 20
print(point) # Output: Point(x=10, y=20)
len(point) # Output: 2
Explanation: The SimpleNamedTuple is initialized with the type name "Point" and fields "x" and "y". Values 10 and 20 are passed as arguments to the constructor, corresponding to the x and y fields respectively. Attribute access works via both name and index.
Example 2:
Input:
type_name = "Color"
fields = ["red", "green", "blue"]
color = SimpleNamedTuple(type_name, fields, 255, 0, 128)
Output:
color.red # Output: 255
color[2] # Output: 128
try:
color.red = 200
except AttributeError as e:
print(e) # Output: can't set attribute
Explanation: Demonstrates attribute access and the immutability constraint. Attempting to modify color.red raises an AttributeError.
Example 3: (Edge Case)
Input:
type_name = "Empty"
fields = []
empty = SimpleNamedTuple(type_name, fields)
Output:
len(empty) # Output: 0
print(empty) # Output: Empty()
Explanation: Shows how the class handles an empty field list.
Constraints
- The class must be implemented in Python.
- The
SimpleNamedTupleclass must be defined. - Instances must be immutable.
- Attribute access must work via both name and index.
- The string representation of an instance must be informative (e.g.,
TypeName(field1=value1, field2=value2, ...)) - The constructor must accept a type string, a list of field names, and a variable number of arguments corresponding to the field values.
Notes
- Focus on the core functionality of
namedtuple: attribute access by name and immutability. You don't need to implement all the features of the standardnamedtuple(e.g.,_fieldsattribute,_make()class method). - Consider using
__slots__to optimize memory usage, similar to hownamedtupleis implemented. This is optional but encouraged. - Think about how to handle the variable number of arguments passed to the constructor. The
*argssyntax will be helpful. - Raising an
AttributeErrorwhen attempting to modify an attribute is crucial for demonstrating immutability.