[Python-checkins] cpython: Factor-out named tuple class definition template strings.

raymond.hettinger python-checkins at python.org
Wed Mar 23 05:23:06 CET 2011


http://hg.python.org/cpython/rev/2778904ba2e2
changeset:   68866:2778904ba2e2
user:        Raymond Hettinger <python at rcn.com>
date:        Tue Mar 22 21:14:41 2011 -0700
summary:
  Factor-out named tuple class definition template strings.

files:
  Lib/collections/__init__.py

diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -233,10 +233,58 @@
 ### namedtuple
 ################################################################################
 
+_class_template = '''\
+class {typename}(tuple):
+    '{typename}({arg_list})'
+
+    __slots__ = ()
+
+    _fields = {field_names!r}
+
+    def __new__(_cls, {arg_list}):
+        'Create new instance of {typename}({arg_list})'
+        return _tuple.__new__(_cls, ({arg_list}))
+
+    @classmethod
+    def _make(cls, iterable, new=tuple.__new__, len=len):
+        'Make a new {typename} object from a sequence or iterable'
+        result = new(cls, iterable)
+        if len(result) != {num_fields:d}:
+            raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
+        return result
+
+    def __repr__(self):
+        'Return a nicely formatted representation string'
+        return self.__class__.__name__ + '({repr_fmt})' % self
+
+    def _asdict(self):
+        'Return a new OrderedDict which maps field names to their values'
+        return OrderedDict(zip(self._fields, self))
+
+    def _replace(_self, **kwds):
+        'Return a new {typename} object replacing specified fields with new values'
+        result = _self._make(map(kwds.pop, {field_names!r}, _self))
+        if kwds:
+            raise ValueError('Got unexpected field names: %r' % kwds.keys())
+        return result
+
+    def __getnewargs__(self):
+        'Return self as a plain tuple.  Used by copy and pickle.'
+        return tuple(self)
+
+{field_defs}
+'''
+
+_repr_template = '{name}=%r'
+
+_field_template = '''\
+    {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}')
+'''
+
 def namedtuple(typename, field_names, verbose=False, rename=False):
     """Returns a new subclass of tuple with named fields.
 
-    >>> Point = namedtuple('Point', 'x y')
+    >>> Point = namedtuple('Point', ['x', 'y'])
     >>> Point.__doc__                   # docstring for the new class
     'Point(x, y)'
     >>> p = Point(11, y=22)             # instantiate with positional args or keywords
@@ -287,66 +335,27 @@
             raise ValueError('Encountered duplicate field name: %r' % name)
         seen_names.add(name)
 
-    # Create and fill-in the class template
-    template = '''class {typename}(tuple):
-        '{typename}({argtxt})'
-
-        __slots__ = ()
-
-        _fields = {field_names!r}
-
-        def __new__(_cls, {argtxt}):
-            'Create new instance of {typename}({argtxt})'
-            return _tuple.__new__(_cls, ({argtxt}))
-
-        @classmethod
-        def _make(cls, iterable, new=tuple.__new__, len=len):
-            'Make a new {typename} object from a sequence or iterable'
-            result = new(cls, iterable)
-            if len(result) != {numfields:d}:
-                raise TypeError('Expected {numfields:d} arguments, got %d' % len(result))
-            return result
-
-        def __repr__(self):
-            'Return a nicely formatted representation string'
-            return self.__class__.__name__ + '({reprtxt})' % self
-
-        def _asdict(self):
-            'Return a new OrderedDict which maps field names to their values'
-            return OrderedDict(zip(self._fields, self))
-
-        def _replace(_self, **kwds):
-            'Return a new {typename} object replacing specified fields with new values'
-            result = _self._make(map(kwds.pop, {field_names!r}, _self))
-            if kwds:
-                raise ValueError('Got unexpected field names: %r' % kwds.keys())
-            return result
-
-        def __getnewargs__(self):
-            'Return self as a plain tuple.  Used by copy and pickle.'
-            return tuple(self)
-
-'''
-    template = template.format(
+    # Fill-in the class template
+    class_definition = _class_template.format(
         typename = typename,
         field_names = field_names,
-        argtxt = repr(field_names).replace("'", "")[1:-1],
-        numfields = len(field_names),
-        reprtxt = ', '.join('{}=%r'.format(name) for name in field_names),
+        num_fields = len(field_names),
+        arg_list = repr(field_names).replace("'", "")[1:-1],
+        repr_fmt = ', '.join(_repr_template.format(name=name) for name in field_names),
+        field_defs = '\n'.join(_field_template.format(index=index, name=name)
+                               for index, name in enumerate(field_names))
     )
-    for i, name in enumerate(field_names):
-        template += "        %s = _property(_itemgetter(%d), doc='Alias for field number %d')\n" % (name, i, i)
     if verbose:
-        print(template)
+        print(class_definition)
 
-    # Execute the template string in a temporary namespace and
+    # Execute the class definition string in a temporary namespace and
     # support tracing utilities by setting a value for frame.f_globals['__name__']
     namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                      OrderedDict=OrderedDict, _property=property, _tuple=tuple)
     try:
-        exec(template, namespace)
+        exec(class_definition, namespace)
     except SyntaxError as e:
-        raise SyntaxError(e.msg + ':\n\n' + template)
+        raise SyntaxError(e.msg + ':\n\n' + class_definition)
     result = namespace[typename]
 
     # For pickling to work, the __module__ variable needs to be set to the frame

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list