Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit052b2df

Browse files
bpo-32492: Tweak _collections._tuplegetter. (GH-11367)
* Replace the docstrings cache with sys.intern().* Improve tests.* Unify names of tp_descr_get and tp_descr_set functions.
1 parent5c117dd commit052b2df

File tree

4 files changed

+75
-37
lines changed

4 files changed

+75
-37
lines changed

‎Lib/collections/__init__.py‎

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,6 @@ def __eq__(self, other):
316316
exceptImportError:
317317
_tuplegetter=lambdaindex,doc:property(_itemgetter(index),doc=doc)
318318

319-
_nt_itemgetters= {}
320-
321319
defnamedtuple(typename,field_names,*,rename=False,defaults=None,module=None):
322320
"""Returns a new subclass of tuple with named fields.
323321
@@ -456,16 +454,9 @@ def __getnewargs__(self):
456454
'_asdict':_asdict,
457455
'__getnewargs__':__getnewargs__,
458456
}
459-
cache=_nt_itemgetters
460457
forindex,nameinenumerate(field_names):
461-
try:
462-
doc=cache[index]
463-
exceptKeyError:
464-
doc=f'Alias for field number{index}'
465-
cache[index]=doc
466-
467-
tuplegetter_object=_tuplegetter(index,doc)
468-
class_namespace[name]=tuplegetter_object
458+
doc=_sys.intern(f'Alias for field number{index}')
459+
class_namespace[name]=_tuplegetter(index,doc)
469460

470461
result=type(typename, (tuple,),class_namespace)
471462

‎Lib/test/test_collections.py‎

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
importcollections
44
importcopy
55
importdoctest
6+
importinspect
67
importoperator
78
importpickle
89
fromrandomimportchoice,randrange
@@ -281,20 +282,50 @@ def test_defaults(self):
281282
self.assertEqual(Point(1), (1,20))
282283
self.assertEqual(Point(), (10,20))
283284

285+
deftest_readonly(self):
286+
Point=namedtuple('Point','x y')
287+
p=Point(11,22)
288+
withself.assertRaises(AttributeError):
289+
p.x=33
290+
withself.assertRaises(AttributeError):
291+
delp.x
292+
withself.assertRaises(TypeError):
293+
p[0]=33
294+
withself.assertRaises(TypeError):
295+
delp[0]
296+
self.assertEqual(p.x,11)
297+
self.assertEqual(p[0],11)
284298

285299
@unittest.skipIf(sys.flags.optimize>=2,
286300
"Docstrings are omitted with -O2 and above")
287301
deftest_factory_doc_attr(self):
288302
Point=namedtuple('Point','x y')
289303
self.assertEqual(Point.__doc__,'Point(x, y)')
304+
Point.__doc__='2D point'
305+
self.assertEqual(Point.__doc__,'2D point')
290306

291307
@unittest.skipIf(sys.flags.optimize>=2,
292308
"Docstrings are omitted with -O2 and above")
293-
deftest_doc_writable(self):
309+
deftest_field_doc(self):
294310
Point=namedtuple('Point','x y')
295311
self.assertEqual(Point.x.__doc__,'Alias for field number 0')
312+
self.assertEqual(Point.y.__doc__,'Alias for field number 1')
296313
Point.x.__doc__='docstring for Point.x'
297314
self.assertEqual(Point.x.__doc__,'docstring for Point.x')
315+
# namedtuple can mutate doc of descriptors independently
316+
Vector=namedtuple('Vector','x y')
317+
self.assertEqual(Vector.x.__doc__,'Alias for field number 0')
318+
Vector.x.__doc__='docstring for Vector.x'
319+
self.assertEqual(Vector.x.__doc__,'docstring for Vector.x')
320+
321+
@support.cpython_only
322+
@unittest.skipIf(sys.flags.optimize>=2,
323+
"Docstrings are omitted with -O2 and above")
324+
deftest_field_doc_reuse(self):
325+
P=namedtuple('P', ['m','n'])
326+
Q=namedtuple('Q', ['o','p'])
327+
self.assertIs(P.m.__doc__,Q.o.__doc__)
328+
self.assertIs(P.n.__doc__,Q.p.__doc__)
298329

299330
deftest_name_fixer(self):
300331
forspec,renamedin [
@@ -319,16 +350,18 @@ def test_instance(self):
319350
self.assertEqual(p,Point(y=22,x=11))
320351
self.assertEqual(p,Point(*(11,22)))
321352
self.assertEqual(p,Point(**dict(x=11,y=22)))
322-
self.assertRaises(TypeError,Point,1)# too few args
323-
self.assertRaises(TypeError,Point,1,2,3)# too many args
324-
self.assertRaises(TypeError,eval,'Point(XXX=1, y=2)',locals())# wrong keyword argument
325-
self.assertRaises(TypeError,eval,'Point(x=1)',locals())# missing keyword argument
353+
self.assertRaises(TypeError,Point,1)# too few args
354+
self.assertRaises(TypeError,Point,1,2,3)# too many args
355+
withself.assertRaises(TypeError):# wrong keyword argument
356+
Point(XXX=1,y=2)
357+
withself.assertRaises(TypeError):# missing keyword argument
358+
Point(x=1)
326359
self.assertEqual(repr(p),'Point(x=11, y=22)')
327360
self.assertNotIn('__weakref__',dir(p))
328-
self.assertEqual(p,Point._make([11,22]))# test _make classmethod
329-
self.assertEqual(p._fields, ('x','y'))# test _fields attribute
330-
self.assertEqual(p._replace(x=1), (1,22))# test _replace method
331-
self.assertEqual(p._asdict(),dict(x=11,y=22))# test _asdict method
361+
self.assertEqual(p,Point._make([11,22]))# test _make classmethod
362+
self.assertEqual(p._fields, ('x','y'))# test _fields attribute
363+
self.assertEqual(p._replace(x=1), (1,22))# test _replace method
364+
self.assertEqual(p._asdict(),dict(x=11,y=22))# test _asdict method
332365

333366
try:
334367
p._replace(x=1,error=2)
@@ -360,11 +393,15 @@ def test_tupleness(self):
360393
x,y=p
361394
self.assertEqual(p, (x,y))# unpacks like a tuple
362395
self.assertEqual((p[0],p[1]), (11,22))# indexable like a tuple
363-
self.assertRaises(IndexError,p.__getitem__,3)
396+
withself.assertRaises(IndexError):
397+
p[3]
398+
self.assertEqual(p[-1],22)
399+
self.assertEqual(hash(p),hash((11,22)))
364400

365401
self.assertEqual(p.x,x)
366402
self.assertEqual(p.y,y)
367-
self.assertRaises(AttributeError,eval,'p.z',locals())
403+
withself.assertRaises(AttributeError):
404+
p.z
368405

369406
deftest_odd_sizes(self):
370407
Zero=namedtuple('Zero','')
@@ -514,13 +551,13 @@ class Point(namedtuple('_Point', ['x', 'y'])):
514551
a.w=5
515552
self.assertEqual(a.__dict__, {'w':5})
516553

517-
deftest_namedtuple_can_mutate_doc_of_descriptors_independently(self):
518-
A=namedtuple('A','x y')
519-
B=namedtuple('B','x y')
520-
A.x.__doc__='foo'
521-
B.x.__doc__='bar'
522-
self.assertEqual(A.x.__doc__,'foo')
523-
self.assertEqual(B.x.__doc__,'bar')
554+
deftest_field_descriptor(self):
555+
Point=namedtuple('Point','x y')
556+
p=Point(11,22)
557+
self.assertTrue(inspect.isdatadescriptor(Point.x))
558+
self.assertEqual(Point.x.__get__(p),11)
559+
self.assertRaises(AttributeError,Point.x.__set__,p,33)
560+
self.assertRaises(AttributeError,Point.x.__delete__,p)
524561

525562

526563
################################################################################

‎Lib/test/test_pydoc.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,16 @@ def test_help_output_redirect(self):
687687
finally:
688688
pydoc.getpager=getpager_old
689689

690+
deftest_namedtuple_fields(self):
691+
Person=namedtuple('Person', ['nickname','firstname'])
692+
withcaptured_stdout()ashelp_io:
693+
pydoc.help(Person)
694+
helptext=help_io.getvalue()
695+
self.assertIn("nickname",helptext)
696+
self.assertIn("firstname",helptext)
697+
self.assertIn("Alias for field number 0",helptext)
698+
self.assertIn("Alias for field number 1",helptext)
699+
690700
deftest_namedtuple_public_underscore(self):
691701
NT=namedtuple('NT', ['abc','def'],rename=True)
692702
withcaptured_stdout()ashelp_io:

‎Modules/_collectionsmodule.c‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,7 +2336,7 @@ _count_elements(PyObject *self, PyObject *args)
23362336
Py_RETURN_NONE;
23372337
}
23382338

2339-
/* Helperfunctions fornamedtuples*/
2339+
/* Helperfunction fornamedtuple() ************************************/
23402340

23412341
typedefstruct {
23422342
PyObject_HEAD
@@ -2369,9 +2369,11 @@ tuplegetter_new_impl(PyTypeObject *type, Py_ssize_t index, PyObject *doc)
23692369
}
23702370

23712371
staticPyObject*
2372-
tuplegetterdescr_get(PyObject*self,PyObject*obj,PyObject*type)
2372+
tuplegetter_descr_get(PyObject*self,PyObject*obj,PyObject*type)
23732373
{
2374+
Py_ssize_tindex= ((_tuplegetterobject*)self)->index;
23742375
PyObject*result;
2376+
23752377
if (obj==NULL) {
23762378
Py_INCREF(self);
23772379
returnself;
@@ -2384,13 +2386,11 @@ tuplegetterdescr_get(PyObject *self, PyObject *obj, PyObject *type)
23842386
PyErr_Format(PyExc_TypeError,
23852387
"descriptor for index '%d' for tuple subclasses "
23862388
"doesn't apply to '%s' object",
2387-
((_tuplegetterobject*)self)->index,
2389+
index,
23882390
obj->ob_type->tp_name);
23892391
returnNULL;
23902392
}
23912393

2392-
Py_ssize_tindex= ((_tuplegetterobject*)self)->index;
2393-
23942394
if (!valid_index(index,PyTuple_GET_SIZE(obj))) {
23952395
PyErr_SetString(PyExc_IndexError,"tuple index out of range");
23962396
returnNULL;
@@ -2402,7 +2402,7 @@ tuplegetterdescr_get(PyObject *self, PyObject *obj, PyObject *type)
24022402
}
24032403

24042404
staticint
2405-
tuplegetter_set(PyObject*self,PyObject*obj,PyObject*value)
2405+
tuplegetter_descr_set(PyObject*self,PyObject*obj,PyObject*value)
24062406
{
24072407
if (value==NULL) {
24082408
PyErr_SetString(PyExc_AttributeError,"can't delete attribute");
@@ -2476,8 +2476,8 @@ static PyTypeObject tuplegetter_type = {
24762476
0,/* tp_getset */
24772477
0,/* tp_base */
24782478
0,/* tp_dict */
2479-
tuplegetterdescr_get,/* tp_descr_get */
2480-
tuplegetter_set,/* tp_descr_set */
2479+
tuplegetter_descr_get,/* tp_descr_get */
2480+
tuplegetter_descr_set,/* tp_descr_set */
24812481
0,/* tp_dictoffset */
24822482
0,/* tp_init */
24832483
0,/* tp_alloc */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2026 Movatter.jp