the PHP ternary operator equivalent on Python

D

Daniel Crespo

Hi!

I would like to know how can I do the PHP ternary operator/statement
(... ? ... : ...) in Python...

I want to something like:

a = {'Huge': (quantity>90) ? True : False}

Any suggestions?

Thanks

Daniel
 
M

Mike Meyer

Daniel Crespo said:
Hi!

I would like to know how can I do the PHP ternary operator/statement
(... ? ... : ...) in Python...

I want to something like:

a = {'Huge': (quantity>90) ? True : False}

Any suggestions?

Lots of ways, depending on your exact needs. What's best for what you
suggest is "a = {Huge : (False, True)[quantity > 90]}". Googling the
python newsgroup will turn up lots of others.

<mike
 
D

David Wahler

Daniel said:
I would like to know how can I do the PHP ternary operator/statement
(... ? ... : ...) in Python...

I want to something like:

a = {'Huge': (quantity>90) ? True : False}

Well, in your example the '>' operator already returns a boolean value
so you can just use it directly. Hoewver, I agree that there are
situations in which a ternary operator would be nice. Unfortunately,
Python doesn't support this directly; the closest approximation I've
found is:
(value_if_false, value_if_true)[boolean_value]

This exploits the fact that False and True are converted to integers as
zero and one, respectively. The downside is that it's really ugly.
Also, it doesn't use minimal evaluation; in other words, if you try an
expression like:

You might think this would return the value of func() if it's callable,
and None otherwise. Unfortunately, func() is evaluated no matter what,
even if the condition is false.

Of course, you can always get around this by doing really cryptic stuff
with lambdas:
(lambda: None, lambda: func())[callable(func)]()

.... but by that point, you're better off just using an if/then/else.

-- David
 
G

gene tani

D

Daniel Crespo

Oh... Well, thanks for that information.

I'll do this then:

def TernaryOperation(condition,true_part,false_part):
if condition:
return True-part
else:
return False-part

a = {'Huge': TernaryOperation(quantity>90,True,False)}

Thank you
 
P

Peter Otten

Daniel said:
Oh... Well, thanks for that information.

I'll do this then:

def TernaryOperation(condition,true_part,false_part):
if condition:
return True-part
else:
return False-part

a = {'Huge': TernaryOperation(quantity>90,True,False)}

By the time it compiles it will do the same as

a = {"Huge": quantity>90}

Consider describing your actual problem and keep in mind that the "ternary
operator" is a means, not an end.

Peter
 
G

Grant Edwards

I would like to know how can I do the PHP ternary operator/statement
(... ? ... : ...) in Python...

The _PHP_ ternary operator (x?y:z)!

Kids these days!
 
D

Daniel Crespo

Hi Peter,

Expand your mind.

a = {'whatever': TernaryOperation(quantity>90,"It is very huge","The
value is correct")}

;-)

thanks for your advice anyway

Daniel
 
S

Steve M

Another way to simulate the ternary operator is this:

a = (quantity > 90 and "It is very huge") or "The value is correct"

You have to be careful of semantics of 'and' and 'or'. But in this case
I wonder why you don't just test whether quantity is greater than 90
and assign the corresponding value to a, e.g., :

if quantity > 90:
a = "It is huge"
else:
a = "Time for tea."


Clarity is a virtue, and simulating ternary operator doesn't always
serve that end.
 
B

bonono

The cleanest(IMO) is this :

a = (predicate and [if_true_expr] or [if_false_expr])[0]

This would give you the necessary "short circuit" behaviour no matter
what.

a = predicate and if_true_expr or if_false_expr

works most of the time but should if_true_expr turns out to be 0 or
something like that(python False equvialent), the if_false_expr will
still be executed, that becomes a logic error. an example :
a = int_str is None and None or int(int_str)


a = [if_false_expr, if_true_expr][predicate]

This doesn't have the "short circuit" feature and the order is
reversed(harder to read for people familiar with ternary operator).
Cannot be used in some case. like this :

a = [0, int(int_str)][int_str is not None]

here int(int_str) may cause exception if None is a valid value.

The lambda form suggested by others is another variant of the first one
above where you get the short circuit feature but too complex to read.

I don't understand why people are so aganst ternary operator. It is a
must for list comprehension/generator expression(and I believe the
reason it has finally been approved), if/else block or try/except just
don't work in these situations.
 
S

Steven D'Aprano

Daniel said:
I would like to know how can I do the PHP ternary operator/statement
(... ? ... : ...) in Python...

I want to something like:

a = {'Huge': (quantity>90) ? True : False}

Well, in your example the '>' operator already returns a boolean value
so you can just use it directly. Hoewver, I agree that there are
situations in which a ternary operator would be nice. Unfortunately,
Python doesn't support this directly; the closest approximation I've
found is:
(value_if_false, value_if_true)[boolean_value]

Which doesn't short-circuit: both value_if_false and value_if_true are
evaluated.

WHY WHY WHY the obsession with one-liners? What is wrong with the good old
fashioned way?

if cond:
x = true_value
else:
x = false_value

It is easy to read, easy to understand, only one of true_value and
false_value is evaluated. It isn't a one-liner. Big deal. Anyone would
think that newlines cost money or that ever time you used one God killed a
kitten.
 
B

bonono

Steven said:
WHY WHY WHY the obsession with one-liners? What is wrong with the good old
fashioned way?

if cond:
x = true_value
else:
x = false_value

It is easy to read, easy to understand, only one of true_value and
false_value is evaluated. It isn't a one-liner. Big deal. Anyone would
think that newlines cost money or that ever time you used one God killed a
kitten.
How do you put this block into list comprehension or generator
expression ? Why the obsession of these block style ?
 
B

bonono

Roy said:
I think the list comprehensions are going to be the death of readable
python programs.
Could be, but seems that someone in charge of the language wants
readable python programs to die then as if list comprehension is not
enough, there comes generator expression and now the formal acceptance
of ternary operator.
 
S

Steven D'Aprano

How do you put this block into list comprehension or generator
expression ? Why the obsession of these block style ?

Why do you assume that everything you need for your list comprehension has
to go into a single line? Chances are your list comp already calls
functions, so just create one more for it to use.


py> def describe(cond):
.... if cond:
.... return "odd"
.... else:
.... return "even"
....
py> L = [describe(n % 2) for n in range(8)]
py> L
['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

One major advantage is that this makes it easier to test your function
describe() in isolation, always a good thing.

Another advantage is that the idiom "call a function" is extensible to
more complex problems:

def describe(n):
if n < 0:
return "negative " + describe(-n)
elif n == 0:
return "zero"
elif n % 2:
return "odd"
else:
return "even"

L = [describe(n) for n in range(8)]

if much easier to understand and follow than using ternary expressions:

# obviously untested
L = ["zero" if n == 0 else \
"negative " + ("odd" if n % 2 else "even") if n < 0 else \
"odd" if n % 2 else "even" for n in range(8)]

Yes, I've seen ternary expressions nested three and even four deep.

I find it fascinating to read Guido's reasoning for introducing a ternary
statement. From the PEP here http://www.python.org/peps/pep-0308.html he
links to this comment of his:

I think Raymond's example is more properly considered an argument for
adding a conditional expression than for removing the current behavior of
the and/or shortcut operators; had we had a conditional expression, he
wouldn't have tried to use the "x and y or z" syntax that bit him.
[end quote]

Looking back to Raymond's example here:
http://mail.python.org/pipermail/python-dev/2005-September/056510.html

I propose that in Py3.0, the "and" and "or" operators be simplified to
always return a Boolean value instead of returning the last evaluated
argument.

1) The construct can be error-prone. When an error occurs it can be
invisible to the person who wrote it. I got bitten in published code
that had survived testing and code review:

def real(self):
'Return a vector with the real part of each input element'
# do not convert integer inputs to floats
return self.map(lambda z: type(z)==types.ComplexType and z.real or z)

The code fails silently when z is (0+4i). It took a good while to trace
down a user reported error (when Matlab results disagreed with my matrix
module results) and determine that the real() method contained an error.
Even when traced down, I found it hard to see the error in the code.
Now that I know what to look for, it has not happened again, but I do
always have to stare hard at any "and/or" group to mentally verify each
case.
[end quote]


Dare I suggest that if Raymond wasn't struggling to force the body of his
function real() to be a one-liner, he wouldn't have tried to use the "x
and y or z" syntax that bit him? Brevity is not always a virtue.
 
B

bonono

Steven said:
Why do you assume that everything you need for your list comprehension has
to go into a single line? Chances are your list comp already calls
functions, so just create one more for it to use.


py> def describe(cond):
... if cond:
... return "odd"
... else:
... return "even"
...
py> L = [describe(n % 2) for n in range(8)]
py> L
['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

this makes me "jump" from the list comprehension to the function,
harder to follow than 'in place', especially when the function is
simple, it is not necessary. What is the reason for introducing list
comprehension and then later, generator expression when :

a=[]
for x in range(8):
a.append(describe(x%2))
return a

and

for x in range(8):
yield describe(x%2)

can do the same thing ?

Doesn't it violate the general idiom that it better has one and only
one way to do certain thing ? I believe part of the reason is that one
doesn't need to "jump" up and down.
One major advantage is that this makes it easier to test your function
describe() in isolation, always a good thing.

Another advantage is that the idiom "call a function" is extensible to
more complex problems:

def describe(n):
if n < 0:
return "negative " + describe(-n)
elif n == 0:
return "zero"
elif n % 2:
return "odd"
else:
return "even"

L = [describe(n) for n in range(8)]

if much easier to understand and follow than using ternary expressions:

# obviously untested
L = ["zero" if n == 0 else \
"negative " + ("odd" if n % 2 else "even") if n < 0 else \
"odd" if n % 2 else "even" for n in range(8)]

Yes, I've seen ternary expressions nested three and even four deep.
Now that is obsession for(and bad use of) one-liner. But picking a bad
example of one liner to rule out its effectiveness and readability is a
stretch I would say.
 
B

bonono

Steven said:
L = ["zero" if n == 0 else \
"negative " + ("odd" if n % 2 else "even") if n < 0 else \
"odd" if n % 2 else "even" for n in range(8)]
BTW, the continuation is not necessary I believe.

[ x==0 and "zero" or ["","-"][x < 0] + ("even", "odd")[x%2] for x in
range(8) ]

isn't too bad. though I like the C one a bit more(as it doesn't
overload the and/or)

[ x==0 ? "zero" : ["","-"][x < 0] + ("even", "odd")[x%2] for x in
range(8) ]

As it is still a very straight forward flow(from left to right, without
"internal decision split in between").
 
D

Daniel Crespo

WHY WHY WHY the obsession with one-liners? What is wrong with the good old
fashioned way?

if cond:
x = true_value
else:
x = false_value

Let me tell you something: I'm not a one-liner coder, but sometimes It
is necesary.
For example:
I need to translate data from a DataField to Another.

def Evaluate(condition,truepart,falsepart):
if condition:
return truepart
else:
return falsepart

dOldDataFields = {}
dNewDataFields = {}

dNewDataFields = {
'CODE': dOldDataFields['CODEDATA'],
'DATE': dOldDataFields['DATE'],
'CONTACT': Evaluate(dOldDataFields['CONTACTTYPE']==2,
dOldDataFields['FIRSTCONTACT'], dOldDataFields['SECONDCONTACT'])
}

With this, I created a new dic very easy, saving in
dNewDataFields['CONTACT'] the value of dOldDataFields['FIRSTCONTACT']
or the value of dOldDataFields['SECONDCONTACT'] depending on
dOldDataFields['CONTACTTYPE']. How you do this in a practic way without
the use of one-line code? It is needed! You can't avoid it! Even using
a = [if_false_expr, if_true_expr][predicate] or a function, you'll
always have to use a one-line code (for this purpose, of course).

Daniel
 
L

Luis M. Gonzalez

This could be done easier this way:

L = [('odd','even')[n%2] for i in range(8)]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top