Conditional elements/arguments

This is one of the reasons why PEP 638 might fill a real gap. As I understand it, we could without much effort have a list! macro that expands into the generator you wrote, and assembles the list.

Yes, exactly this is the reason why I started this analysis conditional-expression/results.md at main ¡ 15r10nk/conditional-expression ¡ GitHub . I want to get a feeling of the impact of this idea.
It is not complete jet, but I hope that it will provide some insightful data.
There is no reason to push this if there are too few use cases, because people would be surprised by the syntax if they are not read/use them frequently.

1 Like

Thank you for this great explanation. This will help me to study the history of this syntax.

I think something like

f(1, 2, conditional!( a = 3 if condition))

Could be transformed to

f(1, 2, **({"a":3} if condition else {}))

This would be crazy. And I fear what would happen if everyone would write such crazy stuff.
One reason I like python is that everything has a well defined simple semantic.

Hmm, I really don’t know if I would love or hate it.

1 Like

Just my opinion: I believe conditional arguments might be a difficult ask to start with. However, something like the collection-if from dart could be a great first step and prove to be quite useful.

After you know how to use it, it’s something that feels natural and at least I use it a lot when writing dart. So much so that I wondered myself why Python can’t do this as well.

What I meant was @Rosuav’s F# example for conditional elements, not the conditional arguments. The syntax is so close that you only need to stick a Yield node into every Expr node you encounter in the AST.

Quick demo using ast.parse on function source
import ast
import inspect

class YieldExpr(ast.NodeTransformer):
    def visit_Expr(self, node):
        node.value = ast.Yield(node.value)
        return node

def list_macro(func):
    source = inspect.getsource(func)
    while source.startswith('@'):
        _, source = source.split('\n', 1)
    node = ast.parse(source)
    newnode = ast.fix_missing_locations(YieldExpr().visit(node))
    results = {}
    exec(compile(node, inspect.getfile(func), 'exec'), func.__globals__, results)
    return list(results[func.__name__]())

foo = False
bar = True
fruits = [4, 5]
status = 400

# as a macro, this could just be "list! items:"
@list_macro
def items():
    6+8 # unconditional emit

    if foo:
        1+1 # conditional emit

    if bar: 
        2+2 # conditional emit

    # emit governed by a loop
    for x in fruits:
        3+x # loop with emit

    # emit governed by a match
    match status:
        case 400:
            400+2 
        case 404:
            404+10

print(items)
# [14, 4, 7, 8, 402]

With PEP 638 that would i) work in a non-horrible manner, ii) be constructed at compile-time, and iii) be available under a good-looking macro name.

1 Like

I like this approach and this concept very much! It would be great if it will be added to Python!

1 Like

A couple of times when I had to write a collection in this style, the way I implemented this was with filter:

h=filter(None, (
    (cookie.name, cookie.value),
    ('path', cookie.path),
    ('domain', cookie.domain),
    ('port', cookie.port) and cookie.port is not None,
    ('path_spec', None) and cookie.path_specified,
    ('port_spec', None) and cookie.port_specified,
    ('domain_dot', None) and cookie.domain_initial_dot,
    ('secure', None) and cookie.secure,
    ('expires', time2isoz(float(cookie.expires))) and cookie.expires,
    ('discard', None) and cookie.discard,
    ('comment', cookie.comment) and cookie.comment,
    ('commenturl', cookie.comment_url) and cookie.comment_url,
))

I do agree that the way you write it here is much more natural-sounding.

Guess what you’re really after is “default argument value”. Similar topics have been raised times and again on this forum. Basically Python lacks a way for callee to identify some arguments of being taken default values by default, and lacks a way for caller to specify a parameter to be passed its default value.

Please use the Help category to ask questions. Do not resurrect a year old topic.