0

Any way to write this in one line in Python, or even better, as an expression instead of a statement?

parts = ['0', '1', 'None', '5', '4']
[int(p) for p in parts]

This of course gives an error,

ValueError: invalid literal for int() with base 10: 'None'

So:

[p=='None' and None or int(p) for p in parts]

Doesn't work because you can't use None with the and/or construct reliably. (Even if p=='None' is true, None is equivalent to false so it goes to the or part.)

[int(p) if p=='None' else None for p in parts]

Also doesn't work. I guess it evaluates int(p) before the conditions? (Seems odd semantics.)

a = []
for p in parts:
    if p=='None': k = None; else: k = int(p)
    a.append(k)

Nope, invalid syntax.

a = []
for p in parts:
    if p=='None':
        k = None;
    else:
        k = int(p)
    a.append(k)

Ah! Finally. But isn't there a shorter way to write such a simple loop?

Steve
  • 8,153
  • 9
  • 44
  • 91

5 Answers5

14

You almost got it right:

[None if p == 'None' else int(p) for p in parts]
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • +1 This is the Python form of the [conditional ternary operator](http://en.wikipedia.org/wiki/Conditional_%28programming%29#As_a_ternary_operator): `when-true if expr else when-false` which maps to the C form of `expr ? when-true : when-false` (the operator is lazy in both languages) –  May 19 '11 at 22:22
  • Or the more powerful (and dangerous) `map(eval, parts)` – 6502 May 19 '11 at 22:24
  • 3
    @6502: Or the less dangerous `map(ast.literal_eval, parts)`. – Sven Marnach May 19 '11 at 22:25
  • Reference: [5.11 Conditional Expressions](http://docs.python.org/reference/expressions.html#conditional-expressions) –  May 19 '11 at 22:38
  • @Sven Marnach: Is there a place to submit a "comment of the day" award? that's brilliant? – SingleNegationElimination May 20 '11 at 01:05
  • A second thought: this seems to count on the fact that None is trivial to evaluate, but I still think it's weird that the part before 'if' gets evaluated first. If I wasn't using None, but calling a function or something, then it would be evaluated regardless of the condition, no? – Steve May 20 '11 at 03:19
  • @Steve: The condition gets evaluated first, and after it only the part the needs to be evaluated. – Sven Marnach May 20 '11 at 10:36
7

Almost had it:

[int(p) if p != 'None' else None for p in parts]
bluepnume
  • 16,460
  • 8
  • 38
  • 48
  • A more legible improvement on Sven Marnach's accepted version. Better to put the common case first. – smci Jul 23 '11 at 00:57
4
[ [int, eval] [p=='None'] (p) for p in parts]

Should be save as eval is only called on string 'None'.

Hyperboreus
  • 822
  • 5
  • 4
  • 1
    I had no idea you could index arrays with booleans. I'd say the syntax is pretty unpythonic, but it's still pretty cool. – Lucas Wiman May 19 '11 at 23:56
  • Nice idea, thanks. I'll probably stick to if-else for clarity but it's a good answer too. – Steve May 20 '11 at 03:16
  • 1
    @intractelicious: See http://stackoverflow.com/questions/3174392/is-it-pythonic-to-use-bools-as-ints/3175293#3175293 for a discussion if this is "Pythonic". – Sven Marnach May 20 '11 at 10:45
  • Actually I personally use these constructs excessively. Let sendSMTP, sendVoice and SensGSM be functions. So I call {'mail': sendSMTP, 'sip': sendVoice, 'sms': SendGSM} [protocol] (message). To send a message depending on its protocol (being in this case one of the dictionary keys.) – Hyperboreus May 20 '11 at 13:29
  • Same, I've always used this construct as a switch-statement replacement. – Matt Luongo Sep 28 '11 at 20:35
0

A simpler solution will be:

parts = ['0', '1', 'None', '5', '4']
[int(p) for p in parts if p.isdigit()]

However, float is not accepted here. If float string(?? I dont know what to call that) to integer is a necessity, you can consider the following:

parts = ['0', '1', 'None', '5', '4']
[int(p.split(".")[0]) for p in parts if p.replace(".", "", 1).isdigit()]
thiruvenkadam
  • 4,170
  • 4
  • 27
  • 26
0

Do you really only have 1 place in your code where you need this transform? If not, define a function and then make it multiple lines, commented, and easy to follow. That way you hide the complexity of your code, and keep the main code simple to read.

xorsyst
  • 7,897
  • 5
  • 39
  • 58