-1

the expression if (mask1 | mask2) is None: returns this error

TypeError: unsupported operand type(s) for |: 'int' and 'NoneType'

How can I check if one of the two variables is None?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
EhsanYaghoubi
  • 145
  • 3
  • 14
  • 3
    should this be true if any of them is `None`, or only if one is `None` but the other is not `None` – Chris Doyle Dec 19 '19 at 16:18
  • 1
    Does this answer your question? [How to test multiple variables against a value?](https://stackoverflow.com/questions/15112125/how-to-test-multiple-variables-against-a-value) It is not an exact duplicate as they are testing for values and OP for `None`, but still the accepted answer applies here also – Tomerikoo Dec 19 '19 at 16:28

4 Answers4

7
if mask1 is None or mask2 is None

Should work

Maxime
  • 818
  • 6
  • 24
2

Not as Pythonic but this would also work

a = 1
b = 2

None in (a, b)
>> False

b = None

None in (a, b)
>> True
gold_cy
  • 13,648
  • 3
  • 23
  • 45
  • IMO, this might be **more** pythonic. See [this answer](https://stackoverflow.com/questions/15112125/how-to-test-multiple-variables-against-a-value) – Tomerikoo Dec 19 '19 at 16:26
  • Nice, but `in` also uses `==`, not `is`, so might fail in the (rather esoteric) case of an object pretending to be `__eq__` to `None` – tobias_k Dec 19 '19 at 16:32
  • correct @tobias_k hence why I mention it might not be as Pythonic although that depends on OP's use case, as is being debated in another answer – gold_cy Dec 19 '19 at 16:33
  • This *will* work. The problem is it is anti-pattern to use equality checks, where identity checks are more appropriate. The place where this will bite you is if you try it with `True` / `False`... ie `True in (a, b)` will return `True`. Equivalently `False in (0, 1)` will return `True`. – James Dec 19 '19 at 16:53
1

Update: OP's exception message indicates he is checking integer vs None. Equality checks will NOT suffice. Consider mask1 = 0, mask2 = None both will fail falsey equality checks.

TypeError: unsupported operand type(s) for |: 'int' and 'NoneType'

If you are testing for identity for an arbitrary number of elements:

any(map(lambda x: x is None, (mask1, mask2, ..., maskN))  # OR operation.

all(map(lambda x: x is None, (mask1, mask2, ..., maskN))  # AND operation.

As user @Jean-François Fabre mentioned get rid of the map / lambda operation:

any(x is None for x in (mask1, mask2, ..., maskN)) # OR

These will all short-circuit because in Python 3 list comprehension will return an iterator that any can evaluate at each step. Same with map / lambda those operations return iterators as well. So which you prefer is a stylistic choice.

If you only have two conditionals, then the other answers (that use identity checks, not falsey checks) will suffice.

James
  • 2,488
  • 2
  • 28
  • 45
  • You don't need `any` **and** `map`, just `any` will do as in the other answers – DeepSpace Dec 19 '19 at 16:20
  • @DeepSpace The other answer, which was deleted because it was incorrect? :p – Konrad Rudolph Dec 19 '19 at 16:22
  • Depends on the OP's use case. If he is checking identity then this approach is correct. If he only needs falsey values then those approaches will work. It is up to the developer to decide what the intent is. – James Dec 19 '19 at 16:22
  • 1
    @KonradRudolph Perhaps a different answer using `any` but *is* correct :P using `any`, `map` **and** a `lambda` seems like a huge overkill for such a simple task. Why not `any(val is None for val in list_of_masks_or_explicit_tuple)` ? We don't know exactly when OP wants this to be `True` but it's irrelevant since it can be easily changed – DeepSpace Dec 19 '19 at 16:25
  • 2
    "Neither of the above will short-circuit though. So you could always optimize using an early exit": not true. It will stop as soon as condition is known – Jean-François Fabre Dec 19 '19 at 16:25
  • 3
    but better written as `any(x is None for x in …)` – Jean-François Fabre Dec 19 '19 at 16:25
  • 2
    @Jean-FrançoisFabre Depends. In Python 2, the `map` is evaluated entirely before checking the `any` (which will short-circuit). But unless noted otherwise we should certainly assume Python 3. – tobias_k Dec 19 '19 at 16:27
  • I think the way I wrote it with the lambda means all values will be evaluated first. In your version, `x is None for x` should return an iterator, which should allow short circuiting. Good suggestion. – James Dec 19 '19 at 16:27
  • 1
    @DeepSpace The generator comprehension code you posted is 100% identical to the `map` code in Python 3, except syntactically. Which to prefer is purely a matter of preference. It’s definitely not conceptually simpler. – Konrad Rudolph Dec 19 '19 at 16:30
  • 1
    @KonradRudolph Python Zen suggests otherwise... – Tomerikoo Dec 19 '19 at 16:32
  • 1
    `map` prevents short-circuiting in Python 2, because it returns a list of Boolean values. In Python 3, `map` creates an iterator that only applies the function as `any` or `all` requests a value. After `any`/`all` stop asking, `map` stops mapping. – chepner Dec 19 '19 at 16:38
  • 1
    It's too early and too cold for me. Yes, lambda / map is identical because they also return iterators. Therefore, both are equivalent as pointed out by Konrad. – James Dec 19 '19 at 16:38
  • 1
    @KonradRudolph *Simple is better than complex*. If they are the same, use the simpler one... – Tomerikoo Dec 19 '19 at 16:39
  • "in Python 3 list comprehension will return an iterator that any can evaluate at each step" That's not entirely correct, either. With a list comprehension, `any([...])` would again not short-circuit (or rather, `any` would, but before that the entire list would be created), but `any(...)` without `[...]` does not use a list comp. but a generator expression. – tobias_k Dec 19 '19 at 16:47
  • @KonradRudolph The difference is more than `syntactically`. Timewise they are not the same. `map` + `lambda` add overhead on large sequences. I tested for a sequence of 1,999,999 non-`None` values + one `None` in the end (worst-case, no short-circuiting). My approach was 2 times faster than the suggested `map` + `lambda`. For more complex use-cases this overhead will be even more significant – DeepSpace Dec 19 '19 at 17:46
0

If you need to check for AND (i.e. all the checks are None):

if all(x is None for x in (mask1, mask2)):
   # execute codes

If you need to check for OR (i.e. any of the checks are None):

if any(x is None for x in (mask1, mask2)):
   # execute codes

You might also consider using set to check:

if {mask1, mask2} == {None}:
   # execute codes for when all are None

if {mask1, mask2} > {None}:
   # execute codes for when any is None

if {mask1, mask2} - {None}:
   # execute codes for when any is not None.
r.ook
  • 13,466
  • 2
  • 22
  • 39