0

I'm trying to figure out if there's a shorter way of writing this if statement (wrote a very basic, unrealistic if statement just so it's easy to see the point.

  x = 3

  if x == 1 or x == 2 or x == 3 or x==4:

     print x

  else:

     print "nope"

I would like to write something along the lines of:

if x == or(1,2,3,4):

is there any way of doing that? Or do I have to write out every option?

Thanks, Sean

Barmar
  • 741,623
  • 53
  • 500
  • 612
user2869231
  • 1,431
  • 5
  • 24
  • 53

3 Answers3

7

you want:

if x in (1, 2, 3, 4):
kindall
  • 178,883
  • 35
  • 278
  • 309
  • 2
    I really miss this in other languages. – Claudiu Oct 15 '13 at 19:25
  • 1
    If you have more than a handful of values, `if x in {1, 2, 3, 4}:` (using a set) is better. But for just four of them, it won't make a difference. – abarnert Oct 15 '13 at 19:27
  • And in that case, if you're using a version of Python without set literals, define the set before the `if` statement. – kindall Oct 15 '13 at 19:30
  • @kindall: Well, `set((1,2,3,4))` isn't that terrible, certainly not the most terrible thing you'll face in Python 2.3… – abarnert Oct 15 '13 at 19:31
  • @abarnert: I thought set literals were much more recent than that, circa 2.7. – DSM Oct 15 '13 at 19:33
  • @Claudiu What languages doesn't have it? Most languages have an idea of "membership in a list." In Haskell, you say `if x \`elem\` [1, 2, 3, 4]`. Even in Java, you could probably do something like `if (Arrays.asList(1, 2, 3, 4).contains(x))`. – kqr Oct 15 '13 at 19:35
  • Yeah, 2.6 doesn't have set literals, they were added in 2.7. – kindall Oct 15 '13 at 19:35
  • @kindall: well, of course you can do it in some way, but it's not as neat. `x in (1, 2, 3, 4)` to me is immediately readable. `Arrays.aslist(1, 2, 3, 4).contains(x)` is not and requires an import. javascript you have to do `[1, 2, 3, 4].indexOf(x) !== -1`, not nearly as nice. the haskell one is pretty good. in C you'd have to write your own function and use arrays, it would be a mess. – Claudiu Oct 15 '13 at 19:43
  • 2
    In Javascript you could do `[1, 2, 3, 4].indexOf(x) + 1` to avoid the ugly `!= -1` although that is arguably even worse. :-) – kindall Oct 15 '13 at 19:56
  • @DSM: But under what circumstances would you be able to upgrade to 2.6, but not to 2.7? When you can't use 2.7, it's because you're stuck with some old version and you have no control over it. – abarnert Oct 15 '13 at 20:06
  • @abarnert: I assumed from your reference to 2.3 that you were implying that to go back to a time when set literals weren't available, you had to go to 2.3, which was so far back that their absence was the least of your concerns. Am I missing something obvious, like usual? – DSM Oct 15 '13 at 20:11
  • @Claudiu Yeah, Java is known for its verbosity and it shows there as well. On the other hand, one can argue that it's neater in the sense that it uses only library functions, and no special syntax. The two things required are a way to write literal lists and a function to tell if an element is a member of said list. Most languages have both of those, even though some are pretty wordy about it (like Java.) C is an exception, of course, although it would maybe be possible to hack it in with a macro... – kqr Oct 15 '13 at 20:13
  • @kqr: i guess in terms of neatness it's ultimately a matter of personal preference. I like simple syntax that is easy to grok. I prefer syntax over function calls, so long as all the syntax is readable. Python's one of my favorites in this respect. – Claudiu Oct 15 '13 at 20:18
  • One thing I do appreciate about Python is how its syntax puts the thing you're looking for first, rather than putting the container first. When you're looking for a needle in a haystack, you're probably more invested in the needle than in the haystack... – kindall Oct 15 '13 at 20:31
  • @DSM: I'm implying that if you don't have set literals, you have some unspecified old version of Python, and it's going to suck in more ways than just set literals not existing. You may be stuck with 2.6 or 2.3 or 2.1, but you're presumably stuck with it. So, either no `str.format` or only half the features; no `with` or single-value-only `with` (and broken `contextlib.nested`), no `io` or slow and broken `io`, no dict and set comps, etc. Even in 2.6, set literals are hardly the biggest thing you'll miss. – abarnert Oct 15 '13 at 20:31
  • @abarnert: wow, that's not at all how I read you. On the bright side, I think that's elliptical enough that I don't feel particularly bad for not having picked up on it. – DSM Oct 15 '13 at 21:08
3

Use the in operator:

if x in range(1, 5)

On Python2 you can use xrange.

On Python 3.2+ it is recommended to use set literals:

if x in {1, 2, 3, 4}:

From docs:

Python’s peephole optimizer now recognizes patterns such xin {1, 2, 3} as being a test for membership in a set of constants. The optimizer recasts the set as a frozenset and stores the pre-built constant. Now that the speed penalty is gone, it is practical to start writing membership tests using set-notation. This style is both semantically clear and operationally fast.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • This is a good solution for Python 3, but the OP is using Python 2, which means it will have to create a list and then search it linearly. Not a horrible problem for only 4 values, but for only 4 values I don't think it's more concise or readable than just writing `[1, 2 ,3, 4]`. – abarnert Oct 15 '13 at 19:26
  • For Python 2, just use `xrange` instead. – chepner Oct 15 '13 at 19:26
  • @chepner: I don't think it's documented anywhere that `in` on an `xrange` is constant time in 2.x. – abarnert Oct 15 '13 at 19:27
  • In fact, it _isn't_ constant time in 2.7; try `%timeit 10000 in xrange(20000)`, `%timeit 100000 in xrange(200000)`, `%timeit 1000000 in xrange(2000000)` and it's clearly linear. – abarnert Oct 15 '13 at 19:28
  • Anyway, for a range with a default `step` and integer values, you can just write `1 <= x < 5`… – abarnert Oct 15 '13 at 19:29
  • OK, I thought I remembered reading once that `in` on `xrange` objects just tested the bounds (which, come to think of it, would be incorrect for a discrete set of values). – chepner Oct 15 '13 at 19:29
  • @chepner: Nope, that's a change made in 3.x (I forget when) and not backported to 2.x. – abarnert Oct 15 '13 at 19:30
  • Your last edit seems more relevant to kindall's answer (and my and his comments underneath it) than to your answer, unless you actually show using a set. – abarnert Oct 15 '13 at 19:32
  • I think a better way to put this is: In Python 3.2+, use set literals for a short list of static values, use range objects for a larger or more dynamic range; in older versions, upgrade to 3.2+, rewrite the check (e.g., as `1 <= x < 5`), or use set literals but just know they won't be as efficient as in 3.2+. – abarnert Oct 15 '13 at 20:09
  • I believe you can also do `if in` for list comprehensions - is that correct? – Eliza Weisman Jan 10 '14 at 18:21
  • @HawkWeisman You mean something like: `if 2 in [x for x in (1,2,3,4)]`? – Ashwini Chaudhary Jan 10 '14 at 18:49
  • @AshwiniChaudhary: yeah - I haven't actually tried it but I see no reason why it shouldn't work. – Eliza Weisman Jan 10 '14 at 19:07
  • @HawkWeisman Yes, this works fine. But, in case the list is large then it's better to [use a generator expression](http://stackoverflow.com/a/11963722/846892). – Ashwini Chaudhary Jan 10 '14 at 19:10
0
if x>=1 or x<=4:

will do the job

  • 1
    Python allows the even shorter `if 1 <= x <= 4`, which also implies `and` (as DSM points out). – chepner Oct 15 '13 at 19:26
  • 4
    What if `x==10`? (IOW, I think you mean `and`.) But this would also let `x==1.5` pass too. – DSM Oct 15 '13 at 19:27
  • I'd actually prefer `if 0 < x < 5` for that type of comparison. – Wayne Werner Oct 15 '13 at 19:30
  • the (1,2,3,4) was just made up numbers; pretend like it's (1, 17, 3, 10000,4) or something. Sorry for being unclear about that, but the "if x in (1,17,3,10000,4)" is the ideal method I was looking for. Thanks, though! – user2869231 Oct 16 '13 at 04:53