checking if two things do not equal None

C

contact.trigon

if (a, b) != (None, None):
or
if a != None != b:

Preference? Pros? Cons? Alternatives?

:D
 
S

Steven D'Aprano

if (a, b) != (None, None):
or
if a != None != b:

Preference? Pros? Cons? Alternatives?

Do you actually want to check for arbitrary objects which may claim to
equal None, or do you want to check for objects which are None?


Nearly always when people test for == to None, they don't really mean it.
They actually want to use an identity test. I'm going to assume the same
holds here.

if not (a is b is None): ...


Or if you prefer:

if a is not b is not None: ...
 
C

contact.trigon

Do you actually want to check for arbitrary objects which may claim to
equal None, or do you want to check for objects which are None?

Arbitrary objects are not a concern.
if not (a is b is None): ...

if a is not b is not None: ...

Thanks for the examples.
 
R

Roy Smith

Johannes Bauer said:
Is this an obfuscated coding contest? Why do you opt for a solution that
one has to at least think 2 seconds about when the simplest solution:

if (a is not None) or (b is not None):

is immediately understandable by everyone?

I agree with that. But
if (a, b) != (None, None):

seems pretty straight-forward to me too. In fact, if anything, it seems
easier to understand than
if (a is not None) or (b is not None):

I certainly agree that things like
if a is not b is not None: ...

belong in an obfuscated coding contest. Code gets read a lot more often
than it get written. Make it dead-ass simple to understand, and future
generations of programmers who inherit your code will thank you for it.
 
J

Johannes Bauer

I agree with that. But


seems pretty straight-forward to me too. In fact, if anything, it seems
easier to understand than

Yes, probably. I liked the original, too. If I were writing the code,
I'd probably try to aim to invert the condition though and simply do

if (a is None) and (b is None)

Which is pretty easy to understand for even a rookie programmer.
I certainly agree that things like


belong in an obfuscated coding contest. Code gets read a lot more often
than it get written. Make it dead-ass simple to understand, and future
generations of programmers who inherit your code will thank you for it.
Absolutely.

Cheers,
Johannes
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
D

Dave Angel

Roy Smith said:
I agree with that. But


seems pretty straight-forward to me too. In fact, if anything, it seems
easier to understand than


I certainly agree that things like


belong in an obfuscated coding contest. Code gets read a lot more often
than it get written. Make it dead-ass simple to understand, and future
generations of programmers who inherit your code will thank you for it.

The other advantage to keeping it simple is it's more than likely
to be right. If we take the original form as the spec, we'll
find that two of the alternatives are not even equivalent.


def trigon1(a, b):
return (a,b) != (None, None) #master

def trigon2(a, b):
return a != None != b. # different

def steven1(a, b):
return not(a is b is None)

def steven2(a, b):
return a is not b is not None #different

def johannes(a, b):
return (a is not None) or (b is not None)

table = [
trigon1,
trigon2,
steven1,
steven2,
johannes
]

for func in table:
print func.__name__
print func(None, None), func(None, 42), func(42, None),
func(42, 42), func(42, "never")
 
J

Johannes Bauer

Yes, probably. I liked the original, too. If I were writing the code,
I'd probably try to aim to invert the condition though and simply do

if (a is None) and (b is None)

Which is pretty easy to understand for even a rookie programmer.

Let me expand on that thought one or two more sentences: Although it may
seem really trivial, inversions ("not") in my opinion can really make
code unreadable. One thing that I regularly see when peer-reviewing code
is something like:

if not feature_disabled:

or one that I've seen in-field (modulo the programming language and the
variable names):

if (not no_delayed_commit) and (not data_unchanged):

instead of:

if immediate_commit and data_changed:

Enough of my two cents for today :)
Cheers,
Johannes


--
Zumindest nicht öffentlich!
Ah, der neueste und bis heute genialste Streich unsere großen
Kosmologen: Die Geheim-Vorhersage.
- Karl Kaos über Rüdiger Thomas in dsa <[email protected]>
 
T

Tim Chase

I agree with that. But


seems pretty straight-forward to me too. In fact, if anything, it
seems easier to understand than

And for cases where you have more than one or two things to test for
None-itude, you could use

if all(x is None for x in [a, b, c, d]):
do_something_if_theyre_all_None()

or

if all(x is not None for x in [a, b, c, d]):
do_something_if_no_Nones()

or

if not any(x is None for x in [a, b, c, d]):
do_something_if_no_Nones()

which I find *much* more readable from a maintenance point of view.

-tkc
 
R

Roy Smith

And for cases where you have more than one or two things to test for
None-itude, you could use

if all(x is None for x in [a, b, c, d]):
do_something_if_theyre_all_None()

I might have written that as:

if set([a, b, c, d]) == set(None)

That's even clearer if you happen to already have the items in an iterable:

if set(conditions) == set(None)
 
T

Tim Chase

And for cases where you have more than one or two things to test
for None-itude, you could use

if all(x is None for x in [a, b, c, d]):
do_something_if_theyre_all_None()

I might have written that as:

if set([a, b, c, d]) == set(None)

That's even clearer if you happen to already have the items in an
iterable:

if set(conditions) == set(None)

Though am I correct that your iteration tests for equality, while
mine tests for identity? Also, my version bails early in the event
quitting early is possible. That's particularly useful in the case
of doing something like

if all(x() is None for x in [func1, func2, func3, costly_func]):
do_something()

-tkc
 
R

Roy Smith

Tim Chase said:
And for cases where you have more than one or two things to test
for None-itude, you could use

if all(x is None for x in [a, b, c, d]):
do_something_if_theyre_all_None()

I might have written that as:

if set([a, b, c, d]) == set(None)

That's even clearer if you happen to already have the items in an
iterable:

if set(conditions) == set(None)

Though am I correct that your iteration tests for equality, while
mine tests for identity?

Hmmm, you're almost certainly correct on that, but you would have to
have a perversely designed class for that to make a difference. I'll
take the increased readability.
Also, my version bails early in the event
quitting early is possible. That's particularly useful in the case
of doing something like

if all(x() is None for x in [func1, func2, func3, costly_func]):
do_something()

Again, you're correct. But, I'll take the increased readability over
the premature optimization :)
 
T

Terry Reedy

if (a, b) != (None, None):
or
if a != None != b:

Preference? Pros? Cons? Alternatives?

if a is not None is not b
==
if a is not None and None is not b
==
if a is not None and b is not None
which is what I would write if not trying to be cute.
a < x < b is more readable as a chained comparison than the double is not.
 
C

Chris Angelico

Though am I correct that your iteration tests for equality, while
mine tests for identity? Also, my version bails early in the event
quitting early is possible. That's particularly useful in the case
of doing something like

if all(x() is None for x in [func1, func2, func3, costly_func]):
do_something()

Presumably you mean to actually call those functions, as checking the
identity of a costly function is still cheap :)

ChrisA
 
C

contact.trigon

Thanks everyone; it has been very educational.
Dave Angel:
...we'll find that two of the alternatives are not even equivalent.

That helped me realize (a,b) != (None, None) is not correct for the function.

It's a case where two parameters have None as the default argument. What I want is to make sure that both are not None. I am now considering:

if None not in (a,b):
or
if (a is not None) and (b is not None):
 
E

Ethan Furman

Is this an obfuscated coding contest? Why do you opt for a solution that
one has to at least think 2 seconds about when the simplest solution:

if (a is not None) or (b is not None):

is immediately understandable by everyone?

+1
 
T

Tim Chase

Though am I correct that your iteration tests for equality, while
mine tests for identity? Also, my version bails early in the
event quitting early is possible. That's particularly useful in
the case of doing something like

if all(x() is None for x in [func1, func2, func3, costly_func]): ^^^
do_something()

Presumably you mean to actually call those functions, as checking
the identity of a costly function is still cheap :)

Which is what I do...calling only those necessary until the all/any
condition has been met. :)

If you create the list of things to iterate over by calling them as
you create the list, then you don't save much of anything. If you
only call until one of them breaks the any/all construct, you save
all the subsequent function calls.

-tkc
 
C

Chris Angelico

Though am I correct that your iteration tests for equality, while
mine tests for identity? Also, my version bails early in the
event quitting early is possible. That's particularly useful in
the case of doing something like

if all(x() is None for x in [func1, func2, func3, costly_func]): ^^^
do_something()

Presumably you mean to actually call those functions, as checking
the identity of a costly function is still cheap :)

Which is what I do...calling only those necessary until the all/any
condition has been met. :)

If you create the list of things to iterate over by calling them as
you create the list, then you don't save much of anything. If you
only call until one of them breaks the any/all construct, you save
all the subsequent function calls.

*facepalm* Yep, you do indeed. My bad! Take no notice of the man
behind the curtain...

ChrisA
 
S

Steven D'Aprano

I certainly agree that things like


belong in an obfuscated coding contest.

Apart from the fact that I got it wrong (that's what happens when I post
at 6am after being up all night, thanks for the correction Lele), if you
consider chained comparisons to be "obfuscated", I think you're not
really fluent at Python. The OP even suggested `a != None != b` so I
think that (s)he at least understands chained comparisons.

However, I agree with Johannes that inverted conditions (using "not") are
sometimes harder to reason about than "regular" conditions.
 
C

Chris Angelico

Apart from the fact that I got it wrong (that's what happens when I post
at 6am after being up all night, thanks for the correction Lele), if you
consider chained comparisons to be "obfuscated", I think you're not
really fluent at Python. The OP even suggested `a != None != b` so I
think that (s)he at least understands chained comparisons.

However, I agree with Johannes that inverted conditions (using "not") are
sometimes harder to reason about than "regular" conditions.

Chained comparisons where you're checking a single variable against
two constants make perfect sense:

2 < x < 5

Chained comparisons where you check a single constant against two
variables don't, so much:

x < 2 < y

What exactly does that mean, and why is it written that way? We can
figure out how the interpreter will parse that, but does that
correspond to the programmer's intention?

It'd be more useful but less clear if one of the conditions points the
other way:

x < 2 > y

which checks that they're both less than two, but IMO in a less-than-clear way.

ChrisA
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top