Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 089ba7f

Browse files
committed
Fix field name conflicts for named tuples.
1 parent e261ae0 commit 089ba7f

4 files changed

Lines changed: 25 additions & 13 deletions

File tree

Doc/library/collections.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,8 @@ Example:
647647
<BLANKLINE>
648648
_fields = ('x', 'y')
649649
<BLANKLINE>
650-
def __new__(cls, x, y):
651-
return tuple.__new__(cls, (x, y))
650+
def __new__(_cls, x, y):
651+
return _tuple.__new__(_cls, (x, y))
652652
<BLANKLINE>
653653
@classmethod
654654
def _make(cls, iterable, new=tuple.__new__, len=len):
@@ -665,18 +665,18 @@ Example:
665665
'Return a new OrderedDict which maps field names to their values'
666666
return OrderedDict(zip(self._fields, self))
667667
<BLANKLINE>
668-
def _replace(self, **kwds):
668+
def _replace(_self, **kwds):
669669
'Return a new Point object replacing specified fields with new values'
670-
result = self._make(map(kwds.pop, ('x', 'y'), self))
670+
result = _self._make(map(kwds.pop, ('x', 'y'), _self))
671671
if kwds:
672672
raise ValueError('Got unexpected field names: %r' % kwds.keys())
673673
return result
674674
<BLANKLINE>
675675
def __getnewargs__(self):
676676
return tuple(self)
677677
<BLANKLINE>
678-
x = property(itemgetter(0))
679-
y = property(itemgetter(1))
678+
x = _property(_itemgetter(0))
679+
y = _property(_itemgetter(1))
680680

681681
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
682682
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)

Lib/collections.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ def namedtuple(typename, field_names, verbose=False, rename=False):
232232
'%(typename)s(%(argtxt)s)' \n
233233
__slots__ = () \n
234234
_fields = %(field_names)r \n
235-
def __new__(cls, %(argtxt)s):
236-
return tuple.__new__(cls, (%(argtxt)s)) \n
235+
def __new__(_cls, %(argtxt)s):
236+
return _tuple.__new__(_cls, (%(argtxt)s)) \n
237237
@classmethod
238238
def _make(cls, iterable, new=tuple.__new__, len=len):
239239
'Make a new %(typename)s object from a sequence or iterable'
@@ -246,23 +246,23 @@ def __repr__(self):
246246
def _asdict(self):
247247
'Return a new OrderedDict which maps field names to their values'
248248
return OrderedDict(zip(self._fields, self)) \n
249-
def _replace(self, **kwds):
249+
def _replace(_self, **kwds):
250250
'Return a new %(typename)s object replacing specified fields with new values'
251-
result = self._make(map(kwds.pop, %(field_names)r, self))
251+
result = _self._make(map(kwds.pop, %(field_names)r, _self))
252252
if kwds:
253253
raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
254254
return result \n
255255
def __getnewargs__(self):
256256
return tuple(self) \n\n''' % locals()
257257
for i, name in enumerate(field_names):
258-
template += ' %s = property(itemgetter(%d))\n' % (name, i)
258+
template += ' %s = _property(_itemgetter(%d))\n' % (name, i)
259259
if verbose:
260260
print(template)
261261

262262
# Execute the template string in a temporary namespace and
263263
# support tracing utilities by setting a value for frame.f_globals['__name__']
264-
namespace = dict(itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
265-
OrderedDict=OrderedDict)
264+
namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
265+
OrderedDict=OrderedDict, _property=property, _tuple=tuple)
266266
try:
267267
exec(template, namespace)
268268
except SyntaxError as e:

Lib/test/test_collections.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,15 @@ def test_copy(self):
173173
self.assertEqual(p, q)
174174
self.assertEqual(p._fields, q._fields)
175175

176+
def test_name_conflicts(self):
177+
# Some names like "self", "cls", "tuple", "itemgetter", and "property"
178+
# failed when used as field names. Test to make sure these now work.
179+
T = namedtuple('T', 'itemgetter property self cls tuple')
180+
t = T(1, 2, 3, 4, 5)
181+
self.assertEqual(t, (1,2,3,4,5))
182+
newt = t._replace(itemgetter=10, property=20, self=30, cls=40, tuple=50)
183+
self.assertEqual(newt, (10,20,30,40,50))
184+
176185
class ABCTestCase(unittest.TestCase):
177186

178187
def validate_abstract_methods(self, abc, *names):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ Library
3737
- Issue #6118: urllib.parse.quote_plus ignored the encoding and errors
3838
arguments for strings with a space in them.
3939

40+
- collections.namedtuple() was not working with the following field
41+
names: cls, self, tuple, itemgetter, and property.
42+
4043
- In unittest, using a skipping decorator on a class is now equivalent to
4144
skipping every test on the class. The ClassTestSuite class has been removed.
4245

0 commit comments

Comments
 (0)