the PHP ternary operator equivalent on Python

Steven D'Aprano steve at
Thu Nov 24 09:12:33 CET 2005

rurpy at wrote:

> Fredrik Lundh wrote:
>>def convert(old):
>>    new = dict(
>>        CODE=old['CODEDATA'],
>>        DATE=old['DATE']
>>        )
>>    if old['CONTACTTYPE'] == 2:
>>        new['CONTACT'] = old['FIRSTCONTACT']
>>    else:
>>        new['CONTACT'] = old['SECONDCONTACT']
>>    return new
> I don't find your code any more readable than the OP's
> equivalent code:
> def convert(old):
>     new = {
> 	CODE: old['CODEDATA'],
> 	DATE: old['DATE'],
> 	    if old['CONTACTTYPE'] == 2 \
> 	    else old['OLDDCONTACT']
> 	}
>     return new

The problem I have with your code is that it is too 
similar to:

def convert(old):
     new = {
         CODE: old['CODEDATA'],
         DATE: old['DATE'],
         CONTACT: old['FIRSTCONTACT'] }
     if old['CONTACTTYPE'] == 2:
     else: old['OLDDCONTACT']
     return new

Yes, the above code is broken. But it *looks* right, at 
first glance, unless you train yourself to never write

if cond: TRUE_CLAUSE

as a two-liner.

Regardless of whatever benefits the ternary operator is 
going to have, in my opinion allowing people to write 
TRUE_CLAUSE if COND else FALSE_CLAUSE will increase the 
amount of poorly written, hard to read code.

> The OPs code make one pass through the dict, your's makes
> two.  

The original code binds a name to an empty dict, then 
rebinds the name to a populated dict.

Your code simply creates the dict in one step.

Fredrik's code creates an initial dict, then adds a new 
key and value to it. That's hardly making two passes 
through the dict -- what does that even mean?

> I do not know what effect (if any) that has in the case of
> a very large dict.

Quick and dirty speed test:

py> from time import time
py> def makedict1():
...     return dict.fromkeys(range(1000))
py> def makedict2():
...     D = {}
...     for i in range(1000):
...             D[i]=None
...     return D
py> assert makedict1() == makedict2()
py> def test(func, n=100):
...     t = time()
...     for i in range(n):
...         tmp = func()
...     return (time() - t)/n
py> test(makedict1)
py> test(makedict2)

That's not timing quite the same thing you refer to, 
but it is suggestive: if you create an empty dict, and 
then populate it one item at a time, it will take 
approximately twice as long as creating the non-empty 
dict directly.

As a very unscientific, system-dependent, statistically 
shoddy ball-park estimate, it looks like each item 
assignment to a pre-existing dict takes less than 
0.0000002s. So if you had a dict and added another 
million items to it, one at a time, it might take an 
extra 0.2s in total more than what it would have taken 
you if you wrote those one million items in your source 

I can live with that.


More information about the Python-list mailing list