<p dir="ltr"><br>
On 13 Jan 2014 11:19, "Andrew Barnert" <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>> wrote:<br>
><br>
> See <a href="http://bugs.python.org/issue20230">http://bugs.python.org/issue20230</a> for the issue and patch. Thanks to Ethan Furman for telling me to post it there instead of here.</p>
<p dir="ltr">This approach sounds good to me for 3.5.</p>
<p dir="ltr">The ABC recipe might make a good addition to the ActiveState cookbook.</p>
<p dir="ltr">Cheers,<br>
Nick.</p>
<p dir="ltr">><br>
><br>
> ----- Original Message -----<br>
> > From: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>><br>
> > To: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>>; "<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>" <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>><br>
> > Cc:<br>
> > Sent: Sunday, January 12, 2014 4:32 PM<br>
> > Subject: Re: [Python-ideas] Making PyStructSequence expose _fields (was Re: namedtuple base class)<br>
> ><br>
> > Here's a quick patch:<br>
> ><br>
> > diff -r bc5f257f5cc1 Lib/test/test_structseq.py<br>
> > --- a/Lib/test/test_structseq.pySun Jan 12 14:12:59 2014 -0800<br>
> > +++ b/Lib/test/test_structseq.pySun Jan 12 16:31:15 2014 -0800<br>
> > @@ -28,6 +28,16 @@<br>
> > for i in range(-len(t), len(t)-1):<br>
> > self.assertEqual(t[i], astuple[i])<br>
> > <br>
> > + def test_fields(self):<br>
> > + t = time.gmtime()<br>
> > + self.assertEqual(t._fields,<br>
> > + ('tm_year', 'tm_mon',<br>
> > 'tm_mday', 'tm_hour', 'tm_min', <br>
> > + 'tm_sec', 'tm_wday',<br>
> > 'tm_yday', 'tm_isdst'))<br>
> > + st = os.stat(__file__)<br>
> > + self.assertIn("st_mode", st._fields)<br>
> > + self.assertIn("st_ino", st._fields)<br>
> > + self.assertIn("st_dev", st._fields)<br>
> > +<br>
> > def test_repr(self):<br>
> > t = time.gmtime()<br>
> > self.assertTrue(repr(t))<br>
> > diff -r bc5f257f5cc1 Objects/structseq.c<br>
> > --- a/Objects/structseq.cSun Jan 12 14:12:59 2014 -0800<br>
> > +++ b/Objects/structseq.cSun Jan 12 16:31:15 2014 -0800<br>
> > @@ -7,6 +7,7 @@<br>
> > static char visible_length_key[] = "n_sequence_fields";<br>
> > static char real_length_key[] = "n_fields";<br>
> > static char unnamed_fields_key[] = "n_unnamed_fields";<br>
> > +static char _fields_key[] = "_fields";<br>
> > <br>
> > /* Fields with this name have only a field index, not a field name.<br>
> > They are only allowed for indices < n_visible_fields. */<br>
> > @@ -14,6 +15,7 @@<br>
> > _Py_IDENTIFIER(n_sequence_fields);<br>
> > _Py_IDENTIFIER(n_fields);<br>
> > _Py_IDENTIFIER(n_unnamed_fields);<br>
> > +_Py_IDENTIFIER(_fields);<br>
> > <br>
> > #define VISIBLE_SIZE(op) Py_SIZE(op)<br>
> > #define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \<br>
> > @@ -327,6 +329,7 @@<br>
> > PyMemberDef* members;<br>
> > int n_members, n_unnamed_members, i, k;<br>
> > PyObject *v;<br>
> > + PyObject *_fields;<br>
> > <br>
> > #ifdef Py_TRACE_REFS<br>
> > /* if the type object was chained, unchain it first<br>
> > @@ -389,6 +392,19 @@<br>
> > SET_DICT_FROM_INT(real_length_key, n_members);<br>
> > SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);<br>
> > <br>
> > + _fields = PyTuple_New(desc->n_in_sequence);<br>
> > + if (!_fields)<br>
> > + return -1;<br>
> > + for (i = 0; i != desc->n_in_sequence; ++i) {<br>
> > + PyObject *field = PyUnicode_FromString(members[i].name);<br>
> > + PyTuple_SET_ITEM(_fields, i, field);<br>
> > + }<br>
> > + if (PyDict_SetItemString(dict, _fields_key, _fields) < 0) {<br>
> > + Py_DECREF(_fields);<br>
> > + return -1;<br>
> > + }<br>
> > + Py_DECREF(_fields);<br>
> > +<br>
> > return 0;<br>
> > }<br>
> > <br>
> > @@ -417,7 +433,8 @@<br>
> > {<br>
> > if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL<br>
> > || _PyUnicode_FromId(&PyId_n_fields) == NULL<br>
> > - || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL)<br>
> > + || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL<br>
> > + || _PyUnicode_FromId(&PyId__fields) == NULL)<br>
> > return -1;<br>
> > <br>
> > return 0;<br>
> ><br>
> ><br>
> ><br>
> ><br>
> > ----- Original Message -----<br>
> >> From: Andrew Barnert <<a href="mailto:abarnert@yahoo.com">abarnert@yahoo.com</a>><br>
> >> To: "<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>" <<a href="mailto:python-ideas@python.org">python-ideas@python.org</a>><br>
> >> Cc:<br>
> >> Sent: Sunday, January 12, 2014 4:17 PM<br>
> >> Subject: [Python-ideas] Making PyStructSequence expose _fields (was Re:<br>
> > namedtuple base class)<br>
> >><br>
> >> I don't think the proposed NamedTuple ABC adds anything on top of duck<br>
> >> typing on _fields (or on whichever other method you need, and possibly<br>
> > checking<br>
> >> for Sequence). As Raymond Hettinger summarized it nicely, namedtuple is a<br>
> >> protocol, not a type.<br>
> >><br>
> >> But I think one of the ideas that came out of that discussion is worth<br>
> > pursuing<br>
> >> on its own: giving a _fields member to every structseq type.<br>
> >><br>
> >> Most of the namedtuple-like classes in the builtins/stdlib, like<br>
> > os.stat_result,<br>
> >> are implemented with PyStructSequence. Since 3.3, that's been a public,<br>
> ><br>
> >> documented protocol. A structseq type is already a tuple. And it stores all<br>
> > the<br>
> >> information needed to expose the fields to Python, it just doesn't<br>
> > expose<br>
> >> them in any way. And making it do so is easy. (Either add it to the type<br>
> >> __dict__ at type creation, or add a getter that generates it on the fly<br>
> > from<br>
> >> tp_members.)<br>
> >><br>
> >> Of course a structseq can do more than a namedtuple. In particular, using a<br>
> ><br>
> >> structseq via its _fields would mean that you miss its<br>
> > "non-sequence"<br>
> >> fields, like st_mtime_ns. But then that's already true for using a<br>
> > structseq<br>
> >> as a sequence, or just looking at its repr, so I don't think that's<br>
> > a<br>
> >> problem. (The "visible fields" are visible for a reason…)<br>
> >><br>
> >> And this still wouldn't mean that _fields is part of the "named<br>
> > tuple<br>
> >> protocol" described in the glossary, just that it's part of<br>
> > structseq<br>
> >> types as well as collections.namedtuple types.<br>
> >><br>
> >> And this wouldn't give structseq an on-demand __dict__ so you can just<br>
> > call<br>
> >> var(s) instead of OrderedDict(zip(s._fields, s)).<br>
> >><br>
> >> Still, it seems like a clear win. A small patch, a bit of extra storage on<br>
> > each<br>
> >> structseq type object (not on the instances), and now you can reflect on<br>
> > the<br>
> >> most common kind of C named tuple types the same way you do on the most<br>
> > common<br>
> >> kind of Python named tuple types.<br>
> >> _______________________________________________<br>
> >> Python-ideas mailing list<br>
> >> <a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
> >> <a href="https://mail.python.org/mailman/listinfo/python-ideas">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> >> Code of Conduct: <a href="http://python.org/psf/codeofconduct/">http://python.org/psf/codeofconduct/</a><br>
> >><br>
> ><br>
> _______________________________________________<br>
> Python-ideas mailing list<br>
> <a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
> <a href="https://mail.python.org/mailman/listinfo/python-ideas">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
> Code of Conduct: <a href="http://python.org/psf/codeofconduct/">http://python.org/psf/codeofconduct/</a></p>