cpython/Lib/collections.py
Christian Heimes 380532117c Merged revisions 59465-59487 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r59467 | georg.brandl | 2007-12-11 17:32:49 +0100 (Tue, 11 Dec 2007) | 2 lines

  Add another GHOP contributor.
........
  r59468 | kurt.kaiser | 2007-12-11 20:35:12 +0100 (Tue, 11 Dec 2007) | 3 lines

  IDLE_tabbedpages.071101.patch Tal Einat
  Cosmetic changes, one bug.  Remove tabpage.py, replaced by tabbedpages.py
........
  r59471 | gerhard.haering | 2007-12-11 22:07:40 +0100 (Tue, 11 Dec 2007) | 9 lines

  Forward-port of commit 59184.

  - Backported a workaround for a bug in SQLite 3.2.x/3.3.x versions where a
    statement recompilation with no bound parameters lead to a segfault
  - Backported a fix necessary because of an SQLite API change in version
    3.5.
    This prevents segfaults when executing empty queries, like our test suite
    does
........
  r59475 | christian.heimes | 2007-12-12 19:09:06 +0100 (Wed, 12 Dec 2007) | 1 line

  Fixed a nasty problem in the xxmodule.c
........
  r59478 | raymond.hettinger | 2007-12-13 01:08:37 +0100 (Thu, 13 Dec 2007) | 1 line

  Fix bug 1604. deque.__init__() did not clear existing contents like list.__init__. Not a backport candidate.
........
  r59480 | alexandre.vassalotti | 2007-12-13 18:58:23 +0100 (Thu, 13 Dec 2007) | 2 lines

  Fix issue #1313119: urlparse "caches" parses regardless of encoding
........
  r59482 | christian.heimes | 2007-12-13 20:23:16 +0100 (Thu, 13 Dec 2007) | 1 line

  Fixed bug #1613: Makefile's VPATH feature is broken
........
  r59484 | guido.van.rossum | 2007-12-13 21:50:10 +0100 (Thu, 13 Dec 2007) | 3 lines

  Patch #1608.  Someone with access to autoconf 2.61 or higher needs to
  run it and check in the resulting configure file.
........
  r59485 | thomas.heller | 2007-12-13 22:20:29 +0100 (Thu, 13 Dec 2007) | 1 line

  Ran autoconf.
........
  r59486 | raymond.hettinger | 2007-12-13 23:55:52 +0100 (Thu, 13 Dec 2007) | 1 line

  Simplify implementation of __replace__()
........
  r59487 | raymond.hettinger | 2007-12-14 00:52:59 +0100 (Fri, 14 Dec 2007) | 1 line

  Small speedup
........
2007-12-14 01:24:44 +00:00

113 lines
4.5 KiB
Python

__all__ = ['deque', 'defaultdict', 'namedtuple']
from _collections import deque, defaultdict
from operator import itemgetter as _itemgetter
from itertools import izip as _izip
from keyword import iskeyword as _iskeyword
import sys as _sys
# For bootstrapping reasons, the collection ABCs are defined in _abcoll.py.
# They should however be considered an integral part of collections.py.
from _abcoll import *
import _abcoll
__all__ += _abcoll.__all__
def namedtuple(typename, field_names, verbose=False):
"""Returns a new subclass of tuple with named fields.
>>> 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
>>> p[0] + p[1] # works just like the tuple (11, 22)
33
>>> x, y = p # unpacks just like a tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessable by name
33
>>> d = p.__asdict__() # convert to a dictionary
>>> d['x']
11
>>> Point(**d) # convert from a dictionary
Point(x=11, y=22)
>>> p.__replace__(x=100) # __replace__() is like str.replace() but targets named fields
Point(x=100, y=22)
"""
# Parse and validate the field names
if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
field_names = tuple(field_names)
for name in (typename,) + field_names:
if not all(c.isalnum() or c=='_' for c in name):
raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
if _iskeyword(name):
raise ValueError('Type names and field names cannot be a keyword: %r' % name)
if name[0].isdigit():
raise ValueError('Type names and field names cannot start with a number: %r' % name)
seen_names = set()
for name in field_names:
if name.startswith('__') and name.endswith('__') and len(name) > 3:
raise ValueError('Field names cannot start and end with double underscores: %r' % name)
if name in seen_names:
raise ValueError('Encountered duplicate field name: %r' % name)
seen_names.add(name)
# Create and fill-in the class template
argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes
reprtxt = ', '.join('%s=%%r' % name for name in field_names)
template = '''class %(typename)s(tuple):
'%(typename)s(%(argtxt)s)'
__slots__ = ()
__fields__ = property(lambda self: %(field_names)r)
def __new__(cls, %(argtxt)s):
return tuple.__new__(cls, (%(argtxt)s))
def __repr__(self):
return '%(typename)s(%(reprtxt)s)' %% self
def __asdict__(self, dict=dict, zip=zip):
'Return a new dict mapping field names to their values'
return dict(zip(%(field_names)r, self))
def __replace__(self, **kwds):
'Return a new %(typename)s object replacing specified fields with new values'
return %(typename)s(**dict(zip(%(field_names)r, self), **kwds)) \n''' % locals()
for i, name in enumerate(field_names):
template += ' %s = property(itemgetter(%d))\n' % (name, i)
if verbose:
print(template)
# Execute the template string in a temporary namespace
namespace = dict(itemgetter=_itemgetter, zip=_izip)
try:
exec(template, namespace)
except SyntaxError as e:
raise SyntaxError(e.message + ':\n' + template)
result = namespace[typename]
# For pickling to work, the __module__ variable needs to be set to the frame
# where the named tuple is created. Bypass this step in enviroments where
# sys._getframe is not defined (Jython for example).
if hasattr(_sys, '_getframe'):
result.__module__ = _sys._getframe(1).f_globals['__name__']
return result
if __name__ == '__main__':
# verify that instances can be pickled
from pickle import loads, dumps
Point = namedtuple('Point', 'x, y', True)
p = Point(x=10, y=20)
assert p == loads(dumps(p))
# test and demonstrate ability to override methods
Point.__repr__ = lambda self: 'Point(%.3f, %.3f)' % self
print(p)
import doctest
TestResults = namedtuple('TestResults', 'failed attempted')
print(TestResults(*doctest.testmod()))