This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add struct.Struct.nmemb
Type: enhancement Stage: patch review
Components: Library (Lib) Versions: Python 3.4
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: georg.brandl, mark.dickinson, meador.inge, pitrou, r.david.murray, rhettinger, skrah
Priority: low Keywords: needs review, patch

Created on 2011-08-12 11:33 by skrah, last changed 2022-04-11 14:57 by admin.

Files
File name Uploaded Description Edit
struct_nmemb.diff skrah, 2011-08-12 11:33 review
Messages (13)
msg141951 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2011-08-12 11:33
It is somewhat complicated to calculate the number of members in
a Struct, so I propose to add Struct.nmemb (in 3.3, 3.2 and 2.7):

>>> import struct
>>> s = struct.Struct("Pxx3Lxxxx3s")
>>> s.size
47
>>> s.nmemb
5


I chose 'nmemb' because it is a standard name in Unix man pages.
Another option would be to spell it out ('nmembers').
msg142025 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2011-08-13 16:12
As a new feature, this could only go into 3.3.
msg142026 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-13 16:31
I had never heard of "nmemb". "nmembers" would be less cryptic.
The patch needs a "versionadded" directive in the docs.
msg142028 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2011-08-13 16:41
While we're at it, let's add str.pbrk() ;)
msg142029 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2011-08-13 17:26
How about __len__()?
msg142031 - (view) Author: Meador Inge (meador.inge) * (Python committer) Date: 2011-08-13 17:52
The functionality part of the patch looks reasonable.  However, the pseudo-randomization in the unit tests seems like a bad idea.  Say someone is adding a new feature X.  Runs the unit tests to find one of them failing.  Then runs them again to investigate and they are now passing.  Unit tests should be repeatable.
msg142073 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2011-08-14 18:03
I like random tests in the stdlib, otherwise the same thing gets tested
over and over again. `make buildbottest` prints the seed, and you can do
it for a single test as well:

 $ ./python -m test -r test_heapq
Using random seed 5857004
[1/1] test_heapq
1 test OK.


It looks like the choice is between s.nmembers and len(s). I thought
about len(s), but since Struct.pack() returns a bytes object, this
might be confusing.

Struct.arity may be another option. This also reflects that pack()
will be an n-ary function for the given format string (and that
Struct is a packing object, not really a struct itself).


Still, probably I'm +0.5 on 'nmembers' compared to the other options.
msg142074 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-08-14 18:17
> It looks like the choice is between s.nmembers and len(s). I thought
> about len(s), but since Struct.pack() returns a bytes object, this
> might be confusing.

I agree there's a risk of confusion between len()-number-of-elements and
size()-number-of-bytes.
We have a similar confusion with the memoryview object and in retrospect
it's often quite misleading.
msg142082 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2011-08-14 20:36
Just to throw in a new name: Struct.nitems would also be possible.
msg142086 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2011-08-14 22:48
In general, I think we can prevent confusion about the meaning of __len__ by sticking to the general rule:  len(object)==len(list(obj)) for anything that produces an iterable result.  In the case of struct, that would be the length of the tuple returned by struct.unpack() or the number of values consumed by struct.pack().

This choice is similar to what was done for collections.Counter where len(Counter(a=10, b=20)) returns 2 (the number of dict keys) rather than 30 (the number of elements in the Bag-like container).  A similar choice   was make for structseq objects when len(ss) == len(iter(ss)) despite there being other non-positional names that are retrievable.

It's true that we get greater clarity by spelling out the specific meaning in the context of structs, as in s.num_members or some such, but we start to lose the advantages of polymorphism and ease of learning/remembering that comes with having consistent API choices.  For any one API such as structs, it probably makes sense to use s.num_members, but for the standard library as a whole, it is probably better to try to make len(obj) have a consistent meaning rather than having many different names for the size of the returned tuple.
msg142157 - (view) Author: Meador Inge (meador.inge) * (Python committer) Date: 2011-08-16 02:44
On Sun, Aug 14, 2011 at 1:03 PM, Stefan Krah <report@bugs.python.org> wrote:
>
> Stefan Krah <stefan-usenet@bytereef.org> added the comment:
>
> I like random tests in the stdlib, otherwise the same thing gets tested
> over and over again. `make buildbottest` prints the seed, and you can do
> it for a single test as well:
>
>  $ ./python -m test -r test_heapq
> Using random seed 5857004
> [1/1] test_heapq
> 1 test OK.

Ah, I see.  Then you can reproduce a run like:

$ ./python -m test -r --randseed=5857004 test_heapq

Perhaps it might be useful to include the failing output in the
assertion message as well
(just in case the seed printing option is not used):

======================================================================
FAIL: test_Struct_nmemb (__main__.StructTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "Lib/test/test_struct.py", line 596, in test_Struct_nmemb
    self.assertEqual(s.nmemb, n, "for struct.Struct(%s)" % fmt)
AssertionError: 3658572 != 3658573 : for
struct.Struct(378576l?403320c266165pb992937H198961PiIL529090sfh887898d796871B)
msg142182 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2011-08-16 10:34
Including the format string in the error output is a good idea. Meador,
was this a constructed failure to show the output or did it really
occur?
msg142199 - (view) Author: Meador Inge (meador.inge) * (Python committer) Date: 2011-08-16 15:13
Stefan, it is a constructed failure (I hacked the unit test to break it).
History
Date User Action Args
2022-04-11 14:57:20adminsetgithub: 56949
2013-07-12 06:37:12rhettingersetassignee: rhettinger ->
versions: + Python 3.4, - Python 3.3
2011-08-16 15:13:50meador.ingesetmessages: + msg142199
2011-08-16 10:34:45skrahsetmessages: + msg142182
2011-08-16 02:44:05meador.ingesetmessages: + msg142157
2011-08-14 22:48:07rhettingersetmessages: + msg142086
2011-08-14 20:36:47skrahsetmessages: + msg142082
2011-08-14 18:17:32pitrousetmessages: + msg142074
2011-08-14 18:03:55skrahsetmessages: + msg142073
2011-08-13 21:41:48rhettingersetpriority: normal -> low
assignee: rhettinger
2011-08-13 17:52:00meador.ingesetnosy: + meador.inge
messages: + msg142031
2011-08-13 17:26:26rhettingersetnosy: + rhettinger
messages: + msg142029
2011-08-13 16:41:00georg.brandlsetnosy: + georg.brandl
messages: + msg142028
2011-08-13 16:31:31pitrousetnosy: + pitrou
messages: + msg142026
2011-08-13 16:12:08r.david.murraysetnosy: + r.david.murray

messages: + msg142025
versions: - Python 3.2
2011-08-12 11:33:27skrahcreate