Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3714,12 +3714,15 @@ copying.
types such as :class:`bytes` and :class:`bytearray`, an element is a single
byte, but other types such as :class:`array.array` may have bigger elements.

``len(view)`` is equal to the length of :class:`~memoryview.tolist`.
If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length
is equal to the number of elements in the view. For higher dimensions,
the length is equal to the length of the nested list representation of
the view. The :class:`~memoryview.itemsize` attribute will give you the
number of bytes in a single element.
``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the documented behavior was changed, it needs a versionchanged directive and an entry in What's New.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I put this in the 3.9 what's new? This sounds like a recipe for merge conflicts, until the rest of the patch has general approval.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checking in on this - what's the procedure for adding a what's new entry if I have no idea which python version this will end up being merged into?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use version 3.10. It cannot go into earlier versions since it's a behavior change. And we have ample time for deliberation on how the documented behavior emerged.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've update it to say 3.11, since it's been two years since I changed it to say 3.10. Let me know if it should be 3.12 instead.

is the nested list representation of the view. If ``view.ndim = 1``,
this is equal to the number of elements in the view.
Comment thread
eric-wieser marked this conversation as resolved.

.. versionchanged:: 3.12
If ``view.ndim == 0``, ``len(view)`` now raises :exc:`TypeError` instead of returning 1.

The :class:`~memoryview.itemsize` attribute will give you the number of
bytes in a single element.

A :class:`memoryview` supports slicing and indexing to expose its data.
One-dimensional slicing will result in a subview::
Expand Down
6 changes: 4 additions & 2 deletions Lib/test/test_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -965,8 +965,10 @@ def check_memoryview(m, expected_readonly=readonly):
self.assertEqual(m.strides, tuple(strides))
self.assertEqual(m.suboffsets, tuple(suboffsets))

n = 1 if ndim == 0 else len(lst)
self.assertEqual(len(m), n)
if ndim == 0:
self.assertRaises(TypeError, len, m)
else:
self.assertEqual(len(m), len(lst))

rep = result.tolist() if fmt else result.tobytes()
self.assertEqual(rep, lst)
Expand Down
24 changes: 11 additions & 13 deletions Lib/test/test_ctypes/test_pep3118.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def test_native_types(self):
if shape:
self.assertEqual(len(v), shape[0])
else:
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
self.assertRaises(TypeError, len, v)
self.assertEqual(v.itemsize, sizeof(itemtp))
self.assertEqual(v.shape, shape)
# XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
Expand All @@ -39,11 +39,10 @@ def test_native_types(self):
# they are always read/write
self.assertFalse(v.readonly)

if v.shape:
n = 1
for dim in v.shape:
n = n * dim
self.assertEqual(n * v.itemsize, len(v.tobytes()))
n = 1
for dim in v.shape:
n = n * dim
self.assertEqual(n * v.itemsize, len(v.tobytes()))
except:
# so that we can see the failing type
print(tp)
Expand All @@ -58,7 +57,7 @@ def test_endian_types(self):
if shape:
self.assertEqual(len(v), shape[0])
else:
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
self.assertRaises(TypeError, len, v)
self.assertEqual(v.itemsize, sizeof(itemtp))
self.assertEqual(v.shape, shape)
# XXX Issue #12851
Expand All @@ -67,11 +66,10 @@ def test_endian_types(self):
# they are always read/write
self.assertFalse(v.readonly)

if v.shape:
n = 1
for dim in v.shape:
n = n * dim
self.assertEqual(n, len(v))
n = 1
for dim in v.shape:
n = n * dim
self.assertEqual(n * v.itemsize, len(v.tobytes()))
except:
# so that we can see the failing type
print(tp)
Expand Down Expand Up @@ -243,7 +241,7 @@ class LEPoint(LittleEndianStructure):
#
endian_types = [
(BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint),
(LEPoint, "T{<l:x:<l:y:}".replace('l', s_long), (), LEPoint),
(LEPoint * 1, "T{<l:x:<l:y:}".replace('l', s_long), (1,), LEPoint),
(POINTER(BEPoint), "&T{>l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)),
(POINTER(LEPoint), "&T{<l:x:<l:y:}".replace('l', s_long), (), POINTER(LEPoint)),
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``len()`` for 0-dimensional :class:`memoryview`` objects (such as ``memoryview(ctypes.c_uint8(42))``) now raises a :exc:`TypeError`.
Previously this returned ``1``, which was not consistent with ``mem_0d[0]`` raising an :exc:`IndexError``.
6 changes: 5 additions & 1 deletion Objects/memoryobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2642,7 +2642,11 @@ static Py_ssize_t
memory_length(PyMemoryViewObject *self)
{
CHECK_RELEASED_INT(self);
return self->view.ndim == 0 ? 1 : self->view.shape[0];
if (self->view.ndim == 0) {
PyErr_SetString(PyExc_TypeError, "0-dim memory has no length");
return -1;
}
return self->view.shape[0];
}

/* As mapping */
Expand Down