Proposed PEP for a Conditional Expression

Alex Martelli aleaxit at yahoo.com
Mon Sep 10 04:15:16 EDT 2001


"Christian Tanzer" <tanzer at swing.co.at> writes:
    ...
"""
> I consider that replacing lambda forms with named functions, in Python, is
> an *excellent* practice, which should be encouraged by all means
necessary.
>  If the lack of a conditional operator does indeed encourage people to
> write more local def's and fewer lambdas, then (to me) that is the "killer
> argument" for not introducing conditional operators.

Conditional expressions provide some nice benefits totally unrelated
to lambdas.
"""
As I went on to say, I find that apart from lambda issues pluses and
minuses are finely balanced.  But if adding a conditional operator
does encourage people to write more lambdas and fewer named functions,
that the "killer argument" against conditionals for me personally.

"""
One example: with a trivial class, one can put expressions into format
directives, like

    "Found %(number)d error%(if number == 1 : '' else : 's')s" % trivial

This doesn't look too attractive if used in a one-liner, put could be
put to very good use for substitution in bigger templates.
"""
Definitely unattractive here -- and you don't really need to
change the Python language, adding complication to it, to get
a similar effect right now.  The __getitem__ method of the
class of 'trivial' can after all perfectly well define whatever
syntax it wants (as long as it's free of ')' charachters:-)
for its 'name' argument.  E.g., assuming it's OK to exclude
'@' and ':' as well, since ')' has to be excluded anyway:

class WithConditionals:

    def __init__(self, globals=globals(), locals=None):
        # you may capture caller's globals/locals here,
        # just as you would if all that trivial did in
        # its __getitem__ was an eval, but that's
        # besides the current issue anyway
        self.globals = globals
        self.locals = locals
        if self.locals is None: self.locals = {}

    def __getitem__(self, name):
        sel = name.split('@',1)
        if len(sel)==1: return eval(name, self.globals, self.locals)
        choices = sel[1].split(':')
        choose = eval(sel[0], self.globals, self.locals)
        if choose<0: choose=0
        elif choose>=len(choices): choose=len(choices)-1
        return eval(choices[choose], self.globals, self.locals)

This is slightly more general than conditionals, as I let
the selector be any integer (folding all <0 to 0, all >=N
to N-1 when there are N choices to select among), but of
course that's up to one's design tastes -- which is the
nice thing about __getitem__ using its own syntax:-).

Anyway, the sample usage of this would be something like:

neat = WithConditionals()
for number in 12,0,5,1:
    print "Found %(number@'no':number)s error%(number@'':'':'s')s" % neat

with output:

D:\>python wc.py
Found 12 errors
Found no error
Found 5 errors
Found 1 error

Whether you like the syntax I've improvised or not, just
as whether you share my preference for "no error" versus
"0 errors", isn't really the point here.  The point, as I
see it, is that, if and when you need special syntax in
a %-format, it's easy and preferable to design it yourself
rather than waiting for Python's own syntax to change to
accomodate you.  In fact, I'd prefer a totally different
approach here, one allowing me to write, e.g.:

print "%(plur_verb number 'Found') %(plur_noun number 'error')s" % neater

with the parser in __getitem__ looking for spaces and using
them, if found, to recognize formatting keywords such as
'plur_verb' -- makes for easier parsing AND for vastly easier
i18n of messages (neater itself would of course use gettext
as needed on the meaning-carrying words such as 'error' or
'Found':-).


Alex






More information about the Python-list mailing list