0
# NamedTuple
1
2
Enhanced tuple implementation with named fields, default values, docstrings, and methods for creating structured data containers. The aenum NamedTuple provides more features than the standard library version.
3
4
## Capabilities
5
6
### NamedTuple Creation
7
8
Factory function for creating NamedTuple classes with named fields and optional features.
9
10
```python { .api }
11
def NamedTuple(typename, fields, *,
12
rename=False, module=None, defaults=None,
13
size=TupleSize.fixed, kwds=False, **kwargs):
14
"""
15
Create a new NamedTuple class.
16
17
Args:
18
typename (str): Name of the new class
19
fields (str | list | dict): Field names or field definitions
20
rename (bool): Rename invalid field names automatically
21
module (str): Module name for the new class
22
defaults (list): Default values for fields
23
size (TupleSize): Size constraint (fixed, minimum, variable)
24
kwds (bool): Allow keyword-only arguments
25
**kwargs: Additional options
26
27
Returns:
28
type: New NamedTuple class with named fields
29
"""
30
```
31
32
#### Basic Usage
33
34
```python
35
from aenum import NamedTuple
36
37
# Simple field names
38
Point = NamedTuple('Point', 'x y')
39
p = Point(10, 20)
40
print(p.x, p.y) # 10 20
41
42
# List of field names
43
Person = NamedTuple('Person', ['name', 'age', 'city'])
44
person = Person('Alice', 30, 'New York')
45
print(person.name) # Alice
46
47
# Field names from string
48
Book = NamedTuple('Book', 'title author isbn year')
49
book = Book('1984', 'George Orwell', '978-0451524935', 1949)
50
```
51
52
#### With Default Values
53
54
```python
55
from aenum import NamedTuple
56
57
# Using defaults parameter
58
Student = NamedTuple('Student', 'name grade school',
59
defaults=['A', 'Unknown School'])
60
s1 = Student('John')
61
print(s1.name, s1.grade, s1.school) # John A Unknown School
62
63
s2 = Student('Jane', 'B+', 'MIT')
64
print(s2.name, s2.grade, s2.school) # Jane B+ MIT
65
66
# Dictionary-style with defaults and docstrings
67
Employee = NamedTuple('Employee', {
68
'name': 'Employee full name',
69
'department': ('Engineering', 'Department name'), # (default, docstring)
70
'salary': (50000, 'Annual salary in USD'),
71
'remote': (False, 'Works remotely')
72
})
73
74
emp = Employee('Bob Smith')
75
print(emp.department) # Engineering
76
print(emp.salary) # 50000
77
```
78
79
### Class-Based NamedTuple
80
81
Define NamedTuple using class syntax with field definitions, methods, and properties.
82
83
```python { .api }
84
class NamedTuple:
85
"""Base class for creating class-based NamedTuples."""
86
87
def _asdict(self):
88
"""Return contents as a dictionary."""
89
90
def _replace(self, **kwargs):
91
"""Return new instance with specified fields replaced."""
92
93
@classmethod
94
def _make(cls, iterable):
95
"""Create instance from iterable."""
96
97
@property
98
def _fields(self):
99
"""Tuple of field names."""
100
```
101
102
#### Usage Example
103
104
```python
105
from aenum import NamedTuple
106
107
class Point3D(NamedTuple):
108
x = 0, 'x coordinate', 0 # index, docstring, default
109
y = 1, 'y coordinate', 0
110
z = 2, 'z coordinate', 0
111
112
def distance_from_origin(self):
113
return (self.x**2 + self.y**2 + self.z**2)**0.5
114
115
def __str__(self):
116
return f'Point3D({self.x}, {self.y}, {self.z})'
117
118
# Usage
119
p1 = Point3D(3, 4, 5)
120
print(p1.distance_from_origin()) # 7.0710678118654755
121
print(p1) # Point3D(3, 4, 5)
122
123
# Default values
124
p2 = Point3D()
125
print(p2) # Point3D(0, 0, 0)
126
127
# Standard methods
128
print(p1._asdict()) # {'x': 3, 'y': 4, 'z': 5}
129
p3 = p1._replace(z=0)
130
print(p3) # Point3D(3, 4, 0)
131
```
132
133
### TupleSize
134
135
Enumeration defining size constraints for NamedTuples.
136
137
```python { .api }
138
class TupleSize(Enum):
139
fixed = 'fixed' # Exact number of fields required
140
minimum = 'minimum' # At least this many fields required
141
variable = 'variable' # Variable number of fields allowed
142
```
143
144
#### Usage Example
145
146
```python
147
from aenum import NamedTuple, TupleSize
148
149
# Fixed size (default)
150
Point = NamedTuple('Point', 'x y', size=TupleSize.fixed)
151
# p = Point(1, 2, 3) # Would raise TypeError
152
153
# Minimum size
154
Args = NamedTuple('Args', 'command', size=TupleSize.minimum)
155
cmd1 = Args('ls')
156
cmd2 = Args('cp', 'file1', 'file2') # Extra args allowed
157
158
# Variable size
159
Data = NamedTuple('Data', 'header', size=TupleSize.variable)
160
data1 = Data('header')
161
data2 = Data('header', 'value1', 'value2', 'value3')
162
```
163
164
### Advanced NamedTuple Features
165
166
#### Field Documentation and Introspection
167
168
```python
169
from aenum import NamedTuple
170
171
# Detailed field definitions
172
User = NamedTuple('User', {
173
'username': (0, 'Unique username for login', None),
174
'email': (1, 'User email address', None),
175
'created_at': (2, 'Account creation timestamp', None),
176
'is_active': (3, 'Account active status', True),
177
'roles': (4, 'List of user roles', lambda: [])
178
})
179
180
# Access field information
181
print(User._field_defaults) # {'is_active': True, 'roles': <lambda>}
182
print(User._field_types) # {} (if no type hints)
183
184
# Create with partial information
185
user = User('alice', 'alice@example.com', '2023-01-01')
186
print(user.is_active) # True
187
print(user.roles) # []
188
```
189
190
#### Inheritance and Extension
191
192
```python
193
from aenum import NamedTuple
194
195
# Base tuple
196
Person = NamedTuple('Person', 'name age')
197
198
# Extend with additional fields
199
Employee = NamedTuple('Employee', Person._fields + ('department', 'salary'))
200
201
emp = Employee('John Doe', 30, 'Engineering', 75000)
202
print(emp.name) # John Doe
203
print(emp.department) # Engineering
204
205
# Class-based inheritance
206
class BaseRecord(NamedTuple):
207
id = 0, 'Record ID', None
208
created = 1, 'Creation timestamp', None
209
210
class UserRecord(BaseRecord):
211
username = 2, 'Username', None
212
email = 3, 'Email address', None
213
214
def __str__(self):
215
return f'User({self.username})'
216
217
user = UserRecord(1, '2023-01-01', 'alice', 'alice@example.com')
218
print(user) # User(alice)
219
```
220
221
#### Custom Methods and Properties
222
223
```python
224
from aenum import NamedTuple
225
226
class Rectangle(NamedTuple):
227
width = 0, 'Rectangle width', 0
228
height = 1, 'Rectangle height', 0
229
230
@property
231
def area(self):
232
return self.width * self.height
233
234
@property
235
def perimeter(self):
236
return 2 * (self.width + self.height)
237
238
def scale(self, factor):
239
return Rectangle(self.width * factor, self.height * factor)
240
241
def is_square(self):
242
return self.width == self.height
243
244
rect = Rectangle(10, 5)
245
print(rect.area) # 50
246
print(rect.perimeter) # 30
247
print(rect.is_square()) # False
248
249
scaled = rect.scale(2)
250
print(scaled) # Rectangle(width=20, height=10)
251
```
252
253
### Practical Patterns
254
255
#### Configuration Objects
256
257
```python
258
from aenum import NamedTuple
259
260
# Database configuration
261
DatabaseConfig = NamedTuple('DatabaseConfig', {
262
'host': ('localhost', 'Database host'),
263
'port': (5432, 'Database port'),
264
'database': (None, 'Database name'),
265
'username': (None, 'Database username'),
266
'password': (None, 'Database password'),
267
'pool_size': (10, 'Connection pool size'),
268
'timeout': (30, 'Connection timeout in seconds')
269
})
270
271
# Create configuration with defaults
272
db_config = DatabaseConfig(
273
database='myapp',
274
username='user',
275
password='secret'
276
)
277
print(db_config.host) # localhost
278
print(db_config.pool_size) # 10
279
```
280
281
#### Data Transfer Objects
282
283
```python
284
from aenum import NamedTuple
285
286
class APIResponse(NamedTuple):
287
status_code = 0, 'HTTP status code', 200
288
data = 1, 'Response data', None
289
headers = 2, 'Response headers', lambda: {}
290
timestamp = 3, 'Response timestamp', None
291
292
@property
293
def is_success(self):
294
return 200 <= self.status_code < 300
295
296
@property
297
def is_error(self):
298
return self.status_code >= 400
299
300
def get_header(self, name):
301
return self.headers.get(name.lower())
302
303
# Usage
304
response = APIResponse(
305
status_code=200,
306
data={'users': [{'id': 1, 'name': 'Alice'}]},
307
headers={'content-type': 'application/json'},
308
timestamp='2023-01-01T10:00:00Z'
309
)
310
311
print(response.is_success) # True
312
print(response.get_header('Content-Type')) # application/json
313
```
314
315
#### Immutable Data Records
316
317
```python
318
from aenum import NamedTuple
319
320
class LogEntry(NamedTuple):
321
timestamp = 0, 'Log timestamp', None
322
level = 1, 'Log level', 'INFO'
323
message = 2, 'Log message', ''
324
module = 3, 'Source module', None
325
line_number = 4, 'Source line number', None
326
327
def __str__(self):
328
return f'[{self.timestamp}] {self.level}: {self.message}'
329
330
def with_context(self, **context):
331
"""Return new log entry with additional context."""
332
updated_message = f"{self.message} | Context: {context}"
333
return self._replace(message=updated_message)
334
335
# Create log entries
336
log1 = LogEntry('2023-01-01 10:00:00', 'ERROR', 'Database connection failed')
337
log2 = log1.with_context(database='postgres', host='localhost')
338
339
print(log1) # [2023-01-01 10:00:00] ERROR: Database connection failed
340
print(log2.message) # Database connection failed | Context: {'database': 'postgres', 'host': 'localhost'}
341
```
342
343
### Integration with Type Hints
344
345
```python
346
from aenum import NamedTuple
347
from typing import Optional, List
348
from datetime import datetime
349
350
# Using with type hints (Python 3.6+)
351
class UserProfile(NamedTuple):
352
username: str = 0, 'Unique username', None
353
email: str = 1, 'Email address', None
354
full_name: Optional[str] = 2, 'Full display name', None
355
tags: List[str] = 3, 'User tags', lambda: []
356
created_at: datetime = 4, 'Creation timestamp', None
357
358
def display_name(self) -> str:
359
return self.full_name or self.username
360
361
# Usage maintains type safety
362
profile = UserProfile(
363
username='alice',
364
email='alice@example.com',
365
full_name='Alice Smith',
366
tags=['developer', 'python'],
367
created_at=datetime.now()
368
)
369
370
print(profile.display_name()) # Alice Smith
371
```
372
373
## Standard NamedTuple Methods
374
375
All NamedTuple instances provide these standard methods:
376
377
```python
378
# Convert to dictionary
379
person_dict = person._asdict()
380
381
# Create new instance with some fields changed
382
updated_person = person._replace(age=31)
383
384
# Create from iterable
385
Person = NamedTuple('Person', 'name age city')
386
person_from_list = Person._make(['Bob', 25, 'Boston'])
387
388
# Field names and defaults
389
print(Person._fields) # ('name', 'age', 'city')
390
print(Person._field_defaults) # {}
391
```