<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>