mirror of
https://github.com/pybind/pybind11.git
synced 2026-03-14 20:27:47 +00:00
feat: add .keys and .values to bind_map (#3310)
* Add `.keys` and `.values` to bind_map Both of these implement views (rather than just iterators), and `.items` is also upgraded to a view. In practical terms, this allows a view to be iterated multiple times and have its size taken, neither of which works with an iterator. The views implement `__len__`, `__iter__`, and the keys view implements `__contains__`. Testing membership also works in item and value views because Python falls back to iteration. This won't be optimal for item values since it's linear rather than O(log n) or O(1), but I didn't fancy trying to get all the corner cases to match Python behaviour (tuple of wrong types, wrong length tuple, not a tuple etc). Missing relative to Python dictionary views is `__reversed__` (only added to Python in 3.8). Implementing that could break code that binds custom map classes which don't provide `rbegin`/`rend` (at least without doing clever things with SFINAE), so I've not tried. The size increase on my system is 131072 bytes, which is rather large (5%) but also suspiciously round (2^17) and makes me suspect some quantisation effect. * bind_map: support any object in __contains__ Add extra overload of `__contains__` (for both the map itself and KeysView) which takes an arbitrary object and returns false. * Take py::object by const reference in __contains__ To keep clang-tidy happy. * Removing stray `py::` (detected via interactive testing in Google environment). Co-authored-by: Ralf W. Grosse-Kunstleve <rwgk@google.com>
This commit is contained in:
@@ -160,15 +160,43 @@ def test_map_string_double():
|
||||
mm["b"] = 2.5
|
||||
|
||||
assert list(mm) == ["a", "b"]
|
||||
assert list(mm.items()) == [("a", 1), ("b", 2.5)]
|
||||
assert str(mm) == "MapStringDouble{a: 1, b: 2.5}"
|
||||
assert "b" in mm
|
||||
assert "c" not in mm
|
||||
assert 123 not in mm
|
||||
|
||||
# Check that keys, values, items are views, not merely iterable
|
||||
keys = mm.keys()
|
||||
values = mm.values()
|
||||
items = mm.items()
|
||||
assert list(keys) == ["a", "b"]
|
||||
assert len(keys) == 2
|
||||
assert "a" in keys
|
||||
assert "c" not in keys
|
||||
assert 123 not in keys
|
||||
assert list(items) == [("a", 1), ("b", 2.5)]
|
||||
assert len(items) == 2
|
||||
assert ("b", 2.5) in items
|
||||
assert "hello" not in items
|
||||
assert ("b", 2.5, None) not in items
|
||||
assert list(values) == [1, 2.5]
|
||||
assert len(values) == 2
|
||||
assert 1 in values
|
||||
assert 2 not in values
|
||||
# Check that views update when the map is updated
|
||||
mm["c"] = -1
|
||||
assert list(keys) == ["a", "b", "c"]
|
||||
assert list(values) == [1, 2.5, -1]
|
||||
assert list(items) == [("a", 1), ("b", 2.5), ("c", -1)]
|
||||
|
||||
um = m.UnorderedMapStringDouble()
|
||||
um["ua"] = 1.1
|
||||
um["ub"] = 2.6
|
||||
|
||||
assert sorted(list(um)) == ["ua", "ub"]
|
||||
assert list(um.keys()) == list(um)
|
||||
assert sorted(list(um.items())) == [("ua", 1.1), ("ub", 2.6)]
|
||||
assert list(zip(um.keys(), um.values())) == list(um.items())
|
||||
assert "UnorderedMapStringDouble" in str(um)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user