Monument ([info]marnanel) wrote,
@ 2002-10-15 12:44:00
Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Python ternary operator
I really want to record a very minor epiphany of last night about Python. For a good while I've wanted something like the C operator ?: (known as the "ternary operator" because it's the only one which considers three things). For the uninitiated, this gives you one result if something's true, and another if it isn't. For example:

(the_user_wants_an_apple?number_of_apples:number_of_oranges)

or, very usefully:

(number==1?"kibbutz":"kibbutzim")

or even, for printing,

(user_is_logged_in?"":"You might want to log in, by the way.")

Well, in Python (as in C), truth is represented by the number one, and falsehood by the number zero. So you can represent ?: by giving a list with two things in (which, traditionally, are number 0 and number 1) and then choosing the member of the list corresponding to the condition. So

['kibbutzim', 'kibbutz'][number==1]

How cool is that?


(Post a new comment)


[info]charles
2002-10-15 05:09 am UTC (link)

I may be wrong here. I'm not a Python hacker, but that looks dangerous.

Mark Pilgrim's Dive Into Python says:

0, '', [], (), {}, and None are false in a boolean context; everything else is true. (Well, almost everything. By default, instances of classes are true in a boolean context, but you can define special methods in your class to make an instance evaluate to false.)

So while (number==1) might return 1 for truth, it might behave unpredictably if you're directly calling a function that you expect to return a boolean, but is really sending back (0 or not-zero).

Of course, I haven't tested this. See disclaimer above. :)

(Reply to this) (Thread)

The and-or trick
[info]charles
2002-10-15 05:14 am UTC (link)
Also from Dive Into Python, his recommendation for a replacement of the ternery operator is The and-or trick. And linked from there, the Python Cookbook discusses alternatives to the and-or trick

(Reply to this) (Parent)(Thread)

Re: The and-or trick
[info]marnanel
2002-10-15 06:56 am UTC (link)
Interesting. The lambda expression given in the Cookbook (foobar = lambda whop: ("foox", "barbar")[whop<="pohrw"]) is pretty similar to the expression I gave in this post, but has the added advantage of using a tuple instead of a list on the left-hand side. The main advantage, I think, is a performance one, but it also looks rather usefully less symmetrical: ('kibbutzim', 'kibbutz')[number==1].

(Reply to this) (Parent)


[info]marnanel
2002-10-15 06:52 am UTC (link)
Sure: I wouldn't use this if I didn't know that the outermost function always returned a boolean. If I was using a function whose return result I wasn't sure of, I'd add ==1 or something.

Thanks for the Dive Into Python link. I've been meaning to read that for some time (having been rather impressed already by his blog).

(Reply to this) (Parent)


[info]hitchhiker
2002-10-15 05:22 am UTC (link)
Ruby has a full fledged ternary operator (and lots of other perlish syntax for people who miss it). OTOH '0' is true, which is slightly hard to get used to.

(Though your workaround reminded me of this rather pretty perl gem:

$min = [$a => $b] -> [$b <= $a];

Shame the -> can't be replaced by a . or something equally symmetrical, but it's still nifty :)
)

(Reply to this)


[info]phlebas
2002-10-15 05:36 am UTC (link)
I thought TRUE was usually -1?

(Reply to this) (Thread)


[info]marnanel
2002-10-15 06:48 am UTC (link)
Not in Python:

Python 2.1.3 (#1, Sep 7 2002, 15:29:56)
[GCC 2.95.4 20011002 (Debian prerelease)] on linux2
Type "copyright", "credits" or "license" for more information.
>>> print 2+2==4
1


Nor in C either (which I took a few years to find out before being asked to stop assuming it by my line manager in a code review). It is in Basic though.

(Reply to this) (Parent)


[info]passage
2002-10-15 07:03 am UTC (link)
You've just spoilt the point of a function I've written (and been using extensively):

def qmark(expression,iftrue,iffalse):
"like expression? iftrue:iffalse"
if expression:
return iftrue
else:
return iffalse

Of course the problem with these is that they both need the arguments to exist (and sometimes the wrong arguement doesn't, then you can't use this one).

The other option is to pass strings and then eval the right one, but that's slow and silly, even if it does work.

Neil

(Reply to this) (Thread)


[info]jaq
2002-10-15 07:42 am UTC (link)
The other problem with this and some of the other alternatives, is that in this example both the true and false expressions are evaluated before the conditional expression is evaluated whereas in the ternary operator, the conditional expression is evaluated first and then only the chosen result expression is evaluated.

(Reply to this) (Parent)(Thread)


[info]passage
2002-10-15 08:27 am UTC (link)
The other problem is ... the problem I already noted?

Okay ...

Neil

(Reply to this) (Parent)(Thread)


[info]jaq
2002-10-15 09:04 am UTC (link)
Ok, not other, but the more general case - it's not just a case of whether the arguments exist, because as general expressions they may have side-effects when evaluated.

(Reply to this) (Parent)(Thread)


[info]passage
2002-10-15 12:18 pm UTC (link)
Ah, okay, fair enough (reading my comment I realise that I didn't express myself as clearly as I ought to have: what I meant was the problem is it evaluates both and this is bad because e.g. if one doesn't exist it crashes.

My bad.)

Neil

(Reply to this) (Parent)


[info]marble
2002-10-15 11:21 am UTC (link)
Reminds me of something I have been known to do in C:
int count=0;
while (worktodo) {
  /* do a little work... */
  printf("\r%c", "\\|/-"[++count%4]);
}

(For any non-C programmers reading that, it displays a twirling baton thing while it's working.)

(Reply to this) (Thread)


[info]marnanel
2002-10-15 12:29 pm UTC (link)
Oo, nice implementation.

(I remember I first saw the baton in UMN gopher, circa 1993. Ah, memories.)

(Reply to this) (Parent)


[info]hitchhiker
2002-10-15 01:27 pm UTC (link)
Nifty!

(Reply to this) (Parent)


Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…