Friday, 25 July 2025

Python Conditional Collection Literals

I've previously mentioned that I regularly visit the discuss python forum (the ideas and PEP's sections). You frequently find there interesting ideas, and though normally they will be rejected and will never be incorporated into python, learning about them is really worth. You'll find ideas that are present in other languages and you were not aware of, and alternative ways to achieve what the idea proposes by using available Python techniques. One of those ideas that recently caught my attention is Conditional collection literals. It proposes a syntax for defining collections literals in which some elements are added or omitted based on one condition. Let's see an example to make it clear:


my_list = [
    elem_1,
    elem_2 if condition,
    elem_3,
]


OK, this is something rarely needed, but the idea looks pretty interesting. Reading the ensuing discussion I've come up with an alternative that looks pretty good to me, just using a sentinel value (OMIT) to indicate that that element must be omitted and function performing the filtering. Let's see it (it's two functions, one for list-like collections and one for dictionaries:


from typing import Any, Callable, Iterable, TypeVar

T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')

# OMIT = object() # better use a class to have it available for typing
class OMIT: pass

def conditional_list(*items: T | type[OMIT]) -> list[T]:
    return [it for it in items if it is not OMIT]

def conditional_dict(*pairs: tuple[K, V] | type[OMIT]) -> dict[K, V]:
    return dict(pair for pair in pairs if pair is not OMIT)


def test_conditional_list():
    l1 = conditional_list(
        "a",
        "b",
        "c" if False else OMIT,
        "d",
        "e" if True else OMIT,
    )
    print(l1)

def test_conditional_dict():
    d1 = conditional_dict(
        ("a", "AA"),
        ("b", "BB"),
        ("c", "CC") if False else OMIT,
        ("d", "DD"),
        ("e", "EE") if True else OMIT,
    )        
    print(d1)

test_conditional_list()
print("------------------------")
test_conditional_dict()

# ['a', 'b', 'd', 'e']
# ------------------------
# {'a': 'AA', 'b': 'BB', 'd': 'DD', 'e': 'EE'}


For the OMIT "sentinel" value I was using initially an object instance, but in order to have something that we can use in the type annotations I've ended up using a class. There's a deferred PEP-661 (but it seems it could be close to being approved by the Steering Council) for adding a utility to define sentinel values. There's an interesting discussion about it here and here

No comments:

Post a Comment