py/objdict: Implement bool and len unary ops for dict views.

Currently, dict views (eg `dict.keys()`, `dict.values()`) do not implement
the `bool` or `len` unary operations.  That may seem like a reasonable
omission for MicroPython to keep code size down, but it actually leads to
silently incorrect bool operations, because by default things are true.

Eg we currently have:

    >>> bool(dict().keys())
    True

which is wrong, it should be `False` because the dict is empty.

This commit implements `bool` and `len` unary operations on dict views by
simply delegating to the existing dict unary op function.

Fixes issue #12385.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George
2025-11-19 14:41:31 +11:00
parent 45938432c6
commit 128420359e
2 changed files with 7 additions and 1 deletions

View File

@@ -521,7 +521,8 @@ static mp_obj_t dict_view_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
if (op == MP_UNARY_OP_HASH && o->kind == MP_DICT_VIEW_VALUES) { if (op == MP_UNARY_OP_HASH && o->kind == MP_DICT_VIEW_VALUES) {
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in); return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);
} }
return MP_OBJ_NULL; // delegate all other ops to dict unary op handler
return dict_unary_op(op, o->dict);
} }
static mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { static mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {

View File

@@ -6,6 +6,11 @@ for m in d.items, d.values, d.keys:
# print a view with more than one item # print a view with more than one item
print({1:1, 2:1}.values()) print({1:1, 2:1}.values())
# `bool` and `len` unary ops
for d in ({}, {1: 2}, {1: 2, 3: 4}):
for op in (bool, len):
print(op(d.keys()), op(d.values()), op(d.items()))
# unsupported binary op on a dict values view # unsupported binary op on a dict values view
try: try:
{1:1}.values() + 1 {1:1}.values() + 1