mirror of https://github.com/python/cpython
gh-83791: Raise TypeError for len(memoryview_0d) (#18463)
Changes the behaviour of `len` on a zero-dimensional `memoryview` to raise `TypeError`. Previously, `len` would return `1`.
This commit is contained in:
parent
caed49448d
commit
3d2a46845b
|
@ -3715,12 +3715,15 @@ copying.
|
||||||
types such as :class:`bytes` and :class:`bytearray`, an element is a single
|
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.
|
byte, but other types such as :class:`array.array` may have bigger elements.
|
||||||
|
|
||||||
``len(view)`` is equal to the length of :class:`~memoryview.tolist`.
|
``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which
|
||||||
If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length
|
is the nested list representation of the view. If ``view.ndim = 1``,
|
||||||
is equal to the number of elements in the view. For higher dimensions,
|
this is equal to the number of elements in the view.
|
||||||
the length is equal to the length of the nested list representation of
|
|
||||||
the view. The :class:`~memoryview.itemsize` attribute will give you the
|
.. versionchanged:: 3.12
|
||||||
number of bytes in a single element.
|
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.
|
A :class:`memoryview` supports slicing and indexing to expose its data.
|
||||||
One-dimensional slicing will result in a subview::
|
One-dimensional slicing will result in a subview::
|
||||||
|
|
|
@ -965,8 +965,10 @@ class TestBufferProtocol(unittest.TestCase):
|
||||||
self.assertEqual(m.strides, tuple(strides))
|
self.assertEqual(m.strides, tuple(strides))
|
||||||
self.assertEqual(m.suboffsets, tuple(suboffsets))
|
self.assertEqual(m.suboffsets, tuple(suboffsets))
|
||||||
|
|
||||||
n = 1 if ndim == 0 else len(lst)
|
if ndim == 0:
|
||||||
self.assertEqual(len(m), n)
|
self.assertRaises(TypeError, len, m)
|
||||||
|
else:
|
||||||
|
self.assertEqual(len(m), len(lst))
|
||||||
|
|
||||||
rep = result.tolist() if fmt else result.tobytes()
|
rep = result.tolist() if fmt else result.tobytes()
|
||||||
self.assertEqual(rep, lst)
|
self.assertEqual(rep, lst)
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Test(unittest.TestCase):
|
||||||
if shape:
|
if shape:
|
||||||
self.assertEqual(len(v), shape[0])
|
self.assertEqual(len(v), shape[0])
|
||||||
else:
|
else:
|
||||||
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
|
self.assertRaises(TypeError, len, v)
|
||||||
self.assertEqual(v.itemsize, sizeof(itemtp))
|
self.assertEqual(v.itemsize, sizeof(itemtp))
|
||||||
self.assertEqual(v.shape, shape)
|
self.assertEqual(v.shape, shape)
|
||||||
# XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
|
# XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
|
||||||
|
@ -39,11 +39,10 @@ class Test(unittest.TestCase):
|
||||||
# they are always read/write
|
# they are always read/write
|
||||||
self.assertFalse(v.readonly)
|
self.assertFalse(v.readonly)
|
||||||
|
|
||||||
if v.shape:
|
n = 1
|
||||||
n = 1
|
for dim in v.shape:
|
||||||
for dim in v.shape:
|
n = n * dim
|
||||||
n = n * dim
|
self.assertEqual(n * v.itemsize, len(v.tobytes()))
|
||||||
self.assertEqual(n * v.itemsize, len(v.tobytes()))
|
|
||||||
except:
|
except:
|
||||||
# so that we can see the failing type
|
# so that we can see the failing type
|
||||||
print(tp)
|
print(tp)
|
||||||
|
@ -58,7 +57,7 @@ class Test(unittest.TestCase):
|
||||||
if shape:
|
if shape:
|
||||||
self.assertEqual(len(v), shape[0])
|
self.assertEqual(len(v), shape[0])
|
||||||
else:
|
else:
|
||||||
self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
|
self.assertRaises(TypeError, len, v)
|
||||||
self.assertEqual(v.itemsize, sizeof(itemtp))
|
self.assertEqual(v.itemsize, sizeof(itemtp))
|
||||||
self.assertEqual(v.shape, shape)
|
self.assertEqual(v.shape, shape)
|
||||||
# XXX Issue #12851
|
# XXX Issue #12851
|
||||||
|
@ -67,11 +66,10 @@ class Test(unittest.TestCase):
|
||||||
# they are always read/write
|
# they are always read/write
|
||||||
self.assertFalse(v.readonly)
|
self.assertFalse(v.readonly)
|
||||||
|
|
||||||
if v.shape:
|
n = 1
|
||||||
n = 1
|
for dim in v.shape:
|
||||||
for dim in v.shape:
|
n = n * dim
|
||||||
n = n * dim
|
self.assertEqual(n * v.itemsize, len(v.tobytes()))
|
||||||
self.assertEqual(n, len(v))
|
|
||||||
except:
|
except:
|
||||||
# so that we can see the failing type
|
# so that we can see the failing type
|
||||||
print(tp)
|
print(tp)
|
||||||
|
@ -243,7 +241,7 @@ class LEPoint(LittleEndianStructure):
|
||||||
#
|
#
|
||||||
endian_types = [
|
endian_types = [
|
||||||
(BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint),
|
(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(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)),
|
(POINTER(LEPoint), "&T{<l:x:<l:y:}".replace('l', s_long), (), POINTER(LEPoint)),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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``.
|
|
@ -2642,7 +2642,11 @@ static Py_ssize_t
|
||||||
memory_length(PyMemoryViewObject *self)
|
memory_length(PyMemoryViewObject *self)
|
||||||
{
|
{
|
||||||
CHECK_RELEASED_INT(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 */
|
/* As mapping */
|
||||||
|
|
Loading…
Reference in New Issue