0

I want a short form the remove an element from a list and use the following:

>>> a = [1, 2, 3, 4]
>>> val = 3
>>> a.remove(val) if val in a else None
>>> a
>>> [1, 2, 4]
>>> val = 10
>>> a.remove(val) if val in a else None
>>> a
>>> [1, 2, 4]

Obviously it works but is it a proper use of a ternary operator?

Bruno Vermeulen
  • 2,970
  • 2
  • 15
  • 29
  • 3
    It will work, but it's not pythonic. Ternaries are intended for use in expressions where the value is needed, not as a substitute for `if` statements. – Barmar Dec 27 '22 at 16:52
  • 3
    What's wrong with the shorter `if val in a: a.remove(val)`? – Barmar Dec 27 '22 at 16:53
  • @Barmar, I believe that's just bad formatting, unless you meant a new line of course... – Nineteendo Dec 27 '22 at 16:55
  • 1
    `val in a and a.remove(val)` is at least a shorter misuse of a construct. – sj95126 Dec 27 '22 at 16:55
  • 1
    @Nineteendo no new line needed. It's valid – roganjosh Dec 27 '22 at 16:56
  • @roganjosh: Convention: C0321 - More than one statement on a single line. – Nineteendo Dec 27 '22 at 17:00
  • 1
    @Nineteendo doesn't make it syntactically invalid – roganjosh Dec 27 '22 at 17:01
  • IF you're okay with removing *ALL* occurrences of the item from the list, then the "pythonic" way of doing this would be `a = [x for x in a if x != val]` – BeRT2me Dec 27 '22 at 17:19
  • Does this answer your question? [Python Ternary Operator Without else](https://stackoverflow.com/questions/12199757/python-ternary-operator-without-else) – BeRT2me Dec 27 '22 at 17:33
  • 1
    Both `a.remove(val) if val in a else None` and `if val in a: a.remove(val)` do two linear scans of `a` when `val` is present. That's redundant, at best. Pythonic, as I understand the term, is `try: a.remove(val) except ValueError: pass` (on four lines). Better: make `a` a set and just write `a.discard(val)`, which is O(1) instead of O(len(a)), and which is the desired no-op if `val` is not there. – rici Dec 27 '22 at 17:34
  • @rici valid, unless you need to represent duplicate values – roganjosh Dec 27 '22 at 17:45
  • @roganjosh: then you use a collections.Counter – rici Dec 27 '22 at 19:25
  • @rici indeed in my case going with a set is the most appropriate as the list is a unique set of indexes. Thanks. – Bruno Vermeulen Dec 28 '22 at 10:42

1 Answers1

4

No, it's not a Pythonic use of a ternary.

Let's put the question aside for a second and look at:

a = [1, 2, 3]
print(a.remove(2))

Well, that gives us None because .remove() works in place.

Now, thinking about a ternary; why might we want that? Usually it would be due to some decision over an assignment:

a = [1, 2, 3]
b = "foo" if a[0] == 1 else "bar"
print(b)

If we apply this kind of model to your ternary, you will always get None. It's somewhat similar to using list comprehensions for side effects.

a = [1, 2, 3]
print(a.remove(2) if 2 in a else None)
print(a.remove(10) if 10 in a else None)

If the operation is always going to return None anyway, then any reader of the code is going to ask why you even bothered with the ternary. There must be some underlying reason, right, because you have an else case even when it's effectively a no-op because the value wasn't found. But I, as a reader, can't determine whether the condition was True or False because I'm going to get None either way.

As stated in the comments, you can do this in one line:

a = [1, 2, 3]
if 2 in a: a.remove(2)
print(a)

Your intent here is more clear because there is no need for a fall-back ternary condition. Even so, chasing lines like this is pointless, but it's better than the ternary.

Not only that but, as @nineteendo points out, you'll have issues with linters by compressing the if check to a single line: see CO321 and, more generally, PEP8

roganjosh
  • 12,594
  • 4
  • 29
  • 46
  • Could you at least mention that multiple statements are against the conventions? – Nineteendo Dec 27 '22 at 17:18
  • Another arguably improper way of doing this: `val in a and a.remove(val)` (Though I thought it was kinda cool) https://stackoverflow.com/a/12199948/11865956 – BeRT2me Dec 27 '22 at 17:30