mirror of
https://github.com/python/cpython.git
synced 2025-09-15 05:06:12 +00:00

svn+ssh://pythondev@svn.python.org/python/trunk ........ r59343 | georg.brandl | 2007-12-05 08:02:47 +0100 (Wed, 05 Dec 2007) | 2 lines Fix typo. ........ r59347 | christian.heimes | 2007-12-05 13:31:44 +0100 (Wed, 05 Dec 2007) | 1 line Fixed quoting and paths in the sqlite project file ........ r59348 | christian.heimes | 2007-12-05 13:45:11 +0100 (Wed, 05 Dec 2007) | 1 line Fixed error in regrtest. I must have missed the spot. ........ r59350 | christian.heimes | 2007-12-05 13:49:14 +0100 (Wed, 05 Dec 2007) | 1 line merge -r59315:59316 from py3k: Fix issue #1553: An errornous __length_hint__ can make list() raise a SystemError ........ r59352 | christian.heimes | 2007-12-05 13:52:34 +0100 (Wed, 05 Dec 2007) | 1 line Added msg to Misc/NEWS ........ r59354 | andrew.kuchling | 2007-12-05 14:27:20 +0100 (Wed, 05 Dec 2007) | 1 line Spelling fix ........ r59356 | georg.brandl | 2007-12-05 18:56:50 +0100 (Wed, 05 Dec 2007) | 3 lines Add examples to csv, pprint and traceback docs. Written by Ross for GHOP. ........ r59358 | raymond.hettinger | 2007-12-05 19:11:08 +0100 (Wed, 05 Dec 2007) | 1 line Error checking was too aggressive (reported by Chris Tismer) ........ r59359 | georg.brandl | 2007-12-05 19:30:48 +0100 (Wed, 05 Dec 2007) | 2 lines Add examples to re docs. Written for GHOP by Dan Finnie. ........ r59366 | georg.brandl | 2007-12-05 20:49:21 +0100 (Wed, 05 Dec 2007) | 2 lines Fix markup. ........ r59367 | christian.heimes | 2007-12-05 20:57:54 +0100 (Wed, 05 Dec 2007) | 1 line Updated documentation and build_tkinter.py script ........ r59368 | georg.brandl | 2007-12-05 21:03:57 +0100 (Wed, 05 Dec 2007) | 2 lines Another markup fix. ........ r59369 | ronald.oussoren | 2007-12-05 21:07:36 +0100 (Wed, 05 Dec 2007) | 7 lines This "fixes" compilation issues for the Carbon._OSA module on OSX Leopard by purging bindings to OSA's debug API's. Those APIs we're completely unsupported on OSX 10.4 and are no longer available on OSX 10.5. Note that this patches a generated file. This is somewhat acceptable because regenerating the file is non-trivial and wouldn't use system headers anyway. ........ r59370 | christian.heimes | 2007-12-05 21:10:38 +0100 (Wed, 05 Dec 2007) | 1 line Fixed bug #1557 by using popen.communicate() before popen.wait() ........
112 lines
4.5 KiB
Python
112 lines
4.5 KiB
Python
__all__ = ['deque', 'defaultdict', 'namedtuple']
|
|
|
|
from _collections import deque, defaultdict
|
|
from operator import itemgetter as _itemgetter
|
|
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(list(zip(%(field_names)r, self)) + list(kwds.items()))) \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)
|
|
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()))
|