@@ -233,10 +233,58 @@ def __eq__(self, other):
233233### namedtuple
234234################################################################################
235235
236+ _class_template = '''\
237+ class {typename}(tuple):
238+ '{typename}({arg_list})'
239+
240+ __slots__ = ()
241+
242+ _fields = {field_names!r}
243+
244+ def __new__(_cls, {arg_list}):
245+ 'Create new instance of {typename}({arg_list})'
246+ return _tuple.__new__(_cls, ({arg_list}))
247+
248+ @classmethod
249+ def _make(cls, iterable, new=tuple.__new__, len=len):
250+ 'Make a new {typename} object from a sequence or iterable'
251+ result = new(cls, iterable)
252+ if len(result) != {num_fields:d}:
253+ raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
254+ return result
255+
256+ def __repr__(self):
257+ 'Return a nicely formatted representation string'
258+ return self.__class__.__name__ + '({repr_fmt})' % self
259+
260+ def _asdict(self):
261+ 'Return a new OrderedDict which maps field names to their values'
262+ return OrderedDict(zip(self._fields, self))
263+
264+ def _replace(_self, **kwds):
265+ 'Return a new {typename} object replacing specified fields with new values'
266+ result = _self._make(map(kwds.pop, {field_names!r}, _self))
267+ if kwds:
268+ raise ValueError('Got unexpected field names: %r' % kwds.keys())
269+ return result
270+
271+ def __getnewargs__(self):
272+ 'Return self as a plain tuple. Used by copy and pickle.'
273+ return tuple(self)
274+
275+ {field_defs}
276+ '''
277+
278+ _repr_template = '{name}=%r'
279+
280+ _field_template = '''\
281+ {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
282+ '''
283+
236284def namedtuple (typename , field_names , verbose = False , rename = False ):
237285 """Returns a new subclass of tuple with named fields.
238286
239- >>> Point = namedtuple('Point', 'x y' )
287+ >>> Point = namedtuple('Point', ['x', 'y'] )
240288 >>> Point.__doc__ # docstring for the new class
241289 'Point(x, y)'
242290 >>> p = Point(11, y=22) # instantiate with positional args or keywords
@@ -287,66 +335,27 @@ def namedtuple(typename, field_names, verbose=False, rename=False):
287335 raise ValueError ('Encountered duplicate field name: %r' % name )
288336 seen_names .add (name )
289337
290- # Create and fill-in the class template
291- template = '''class {typename}(tuple):
292- '{typename}({argtxt})'
293-
294- __slots__ = ()
295-
296- _fields = {field_names!r}
297-
298- def __new__(_cls, {argtxt}):
299- 'Create new instance of {typename}({argtxt})'
300- return _tuple.__new__(_cls, ({argtxt}))
301-
302- @classmethod
303- def _make(cls, iterable, new=tuple.__new__, len=len):
304- 'Make a new {typename} object from a sequence or iterable'
305- result = new(cls, iterable)
306- if len(result) != {numfields:d}:
307- raise TypeError('Expected {numfields:d} arguments, got %d' % len(result))
308- return result
309-
310- def __repr__(self):
311- 'Return a nicely formatted representation string'
312- return self.__class__.__name__ + '({reprtxt})' % self
313-
314- def _asdict(self):
315- 'Return a new OrderedDict which maps field names to their values'
316- return OrderedDict(zip(self._fields, self))
317-
318- def _replace(_self, **kwds):
319- 'Return a new {typename} object replacing specified fields with new values'
320- result = _self._make(map(kwds.pop, {field_names!r}, _self))
321- if kwds:
322- raise ValueError('Got unexpected field names: %r' % kwds.keys())
323- return result
324-
325- def __getnewargs__(self):
326- 'Return self as a plain tuple. Used by copy and pickle.'
327- return tuple(self)
328-
329- '''
330- template = template .format (
338+ # Fill-in the class template
339+ class_definition = _class_template .format (
331340 typename = typename ,
332341 field_names = field_names ,
333- argtxt = repr (field_names ).replace ("'" , "" )[1 :- 1 ],
334- numfields = len (field_names ),
335- reprtxt = ', ' .join ('{}=%r' .format (name ) for name in field_names ),
342+ num_fields = len (field_names ),
343+ arg_list = repr (field_names ).replace ("'" , "" )[1 :- 1 ],
344+ repr_fmt = ', ' .join (_repr_template .format (name = name ) for name in field_names ),
345+ field_defs = '\n ' .join (_field_template .format (index = index , name = name )
346+ for index , name in enumerate (field_names ))
336347 )
337- for i , name in enumerate (field_names ):
338- template += " %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n " % (name , i , i )
339348 if verbose :
340- print (template )
349+ print (class_definition )
341350
342- # Execute the template string in a temporary namespace and
351+ # Execute the class definition string in a temporary namespace and
343352 # support tracing utilities by setting a value for frame.f_globals['__name__']
344353 namespace = dict (_itemgetter = _itemgetter , __name__ = 'namedtuple_%s' % typename ,
345354 OrderedDict = OrderedDict , _property = property , _tuple = tuple )
346355 try :
347- exec (template , namespace )
356+ exec (class_definition , namespace )
348357 except SyntaxError as e :
349- raise SyntaxError (e .msg + ':\n \n ' + template )
358+ raise SyntaxError (e .msg + ':\n \n ' + class_definition )
350359 result = namespace [typename ]
351360
352361 # For pickling to work, the __module__ variable needs to be set to the frame
0 commit comments