From b4b2292488dc59892ed0ec1c1fe17c4ba663f5ef Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 1 Sep 2018 01:19:16 +0200 Subject: [PATCH] relax operator[] for tuples, lists, and sequences object_api::operator[] has a powerful overload for py::handle that can accept slices, tuples (for NumPy), etc. Lists, sequences, and tuples provide their own specialized operator[], which unfortunately disables this functionality. This is accidental, and the purpose of this commit is to re-enable the more general behavior. This commit is tangentially related to the previous one in that it makes py::handle/py::object et al. behave more like their Python counterparts. --- include/pybind11/pytypes.h | 3 +++ tests/test_pytypes.cpp | 4 ++++ tests/test_pytypes.py | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index ab804b100..fa5ed7cbd 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -1183,6 +1183,7 @@ public: } size_t size() const { return (size_t) PyTuple_Size(m_ptr); } detail::tuple_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } detail::tuple_iterator begin() const { return {*this, 0}; } detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; } }; @@ -1220,6 +1221,7 @@ public: PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check) size_t size() const { return (size_t) PySequence_Size(m_ptr); } detail::sequence_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } detail::sequence_iterator begin() const { return {*this, 0}; } detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; } }; @@ -1232,6 +1234,7 @@ public: } size_t size() const { return (size_t) PyList_Size(m_ptr); } detail::list_accessor operator[](size_t index) const { return {*this, index}; } + detail::item_accessor operator[](handle h) const { return object::operator[](h); } detail::list_iterator begin() const { return {*this, 0}; } detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; } template void append(T &&val) const { diff --git a/tests/test_pytypes.cpp b/tests/test_pytypes.cpp index af7391d88..e6c955ff9 100644 --- a/tests/test_pytypes.cpp +++ b/tests/test_pytypes.cpp @@ -289,4 +289,8 @@ TEST_SUBMODULE(pytypes, m) { l.append(a << b); return l; }); + + m.def("test_list_slicing", [](py::list a) { + return a[py::slice(0, -1, 2)]; + }); } diff --git a/tests/test_pytypes.py b/tests/test_pytypes.py index 661190907..0116d4ef2 100644 --- a/tests/test_pytypes.py +++ b/tests/test_pytypes.py @@ -246,3 +246,8 @@ def test_number_protocol(): li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b, a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b] assert m.test_number_protocol(a, b) == li + + +def test_list_slicing(): + li = list(range(100)) + assert li[::2] == m.test_list_slicing(li)