开发者

Python things which are neither True nor False

I just found this :

a = (None,)
print (a is True)
print (a is False)
print (a == True)
print (a == False)
print (a == None)
print (a is None)
if a : print "hello"
if not a : print "goodbye"

which produces :

False
False
False
False
False
False
hello

So a neither is, nor equals True nor False, but acts as True开发者_如何学编程 in an if statement.

Why?

Update :

actually, I've just realized that this isn't as obscure as I thought. I get the same result for a=2, as well (though not for a=0 or a=1, which are considered equal to False and True respectively)


I find almost all the explanations here unhelpful, so here is another try:

The confusion here is based on that testing with "is", "==" and "if" are three different things.

  • "is" tests identity, that is, if it's the same object. That is obviously not true in this case.
  • "==" tests value equality, and obviously the only built in objects with the values of True and False are the object True and False (with the exception of the numbers 0 and 1, of any numeric type).

And here comes the important part:

  • 'if' tests on boolean values. That means that whatever expression you give it, it will be converted to either True or False. You can make the same with bool(). And bool((None,)) will return True. The things that will evaluate to False is listed in the docs (linked to by others here)

Now maybe this is only more clear in my head, but at least I tried. :)


a is a one-member tuple, which evaluates to True. is test identity of the object, therefore, you get False in all those test. == test equality of the objects, therefore, you get False again.

in if statement a __bool__ (or __nonzero__) used to evaluate the object, for a non-empty tuple it should return True, therefore you get True. hope that answers your question.

edit: the reason True and False are equal to 1 and 0 respectively is because bool type implemented as a subclass of int type.


Things in python don't have to be one of True or False.

When they're used as a text expression for if/while loops, they're converted to booleans. You can't use is or == to test what they evaluate to. You use bool( thing )

>>> a = (None,)
>>> bool(a)
True

Also note:

>>> 10 == True
False
>>> 10 is True
False
>>> bool(10)
True


TL;DR:

if and == are completely different operations. The if checks the truth value of a variable while == compares two variables. is also compares two variables but it compares if both reference the same object.

So it makes no sense to compare a variable with True, False or None to check it's truth value.

What happens when if is used on a variable?

In Python a check like if implicitly gets the bool of the argument. So

if something:

will be (under the hood) executed like:

if bool(something):

Note that you should never use the latter in your code because it's considered less pythonic and it's slower (because Python then uses two bools: bool(bool(something))). Always use the if something.

If you're interested in how it's evaluated by CPython 3.6:

Python things which are neither True nor False

Note that CPython doesn't exactly use hasattr here. It does check if the type of x implements the method but without going through the __getattribute__ method (hasattr would use that).

In Python2 the method was called __nonzero__ and not __bool__

What happens when variables are compared using ==?

The == will check for equality (often also called "value equality"). However this equality check doesn't coerce the operands (unlike in other programming languages). The value equality in Python is explicitly implemented. So you can do:

>>> 1 == True  # because bool subclasses int, True is equal to 1 (and False to 0)
True

>>> 1.0 == True  # because float implements __eq__ with int
True

>>> 1+1j == True  # because complex implements __eq__ with int
True

However == will default to reference comparison (is) if the comparison isn't implemented by either operand. That's why:

>>> (None, ) == True
False

Because tuple doesn't "support" equality with int and vise-versa. Note that even comparing lists to tuples is "unsupported":

>>> [None] == (None, )
False

Just in case you're interested this is how CPython (3.6) implements equality (the orange arrows indicate if an operation returned the NotImplemented constant):

Python things which are neither True nor False

That's only roughly correct because CPython also checks if the type() of value1 or value2 implements __eq__ (without going through the __getattribute__ method!) before it's called (if it exists) or skipped (if it doesn't exist).

Note that the behavior in Python2 was significantly more lengthy (at least if the methods returned NotImplemented) and Python 2 also supported __cmp__,

What happens when variables are compared using is?

is is generally referred to as reference equality comparison operator. It only returns True if both variables refer to exactly the same object. In general variables that hold the same value can nevertheless refer to different objects:

>>> 1 is 1.  # same value, different types
False

>>> a = 500
>>> a is 500  # same value, same type, different instances
False

Note that CPython uses cached values, so sometimes variables that "should" be different instances are actually the same instance. That's why I didn't use 500 is 500 (literals with the same value in the same line are always equal) and why I couldn't use 1 as example (because CPython re-uses the values -5 to 256).

But back to your comparisons: is compares references, that means it's not enough if both operands have the same type and value but they have to be the same reference. Given that they didn't even have the same type (you're comparing tuple with bool and NoneType objects) it's impossible that is would return True.

Note that True, False and None (and also NotImplemented and Ellipsis) are constants and singletons in CPython. That's not just an optimization in these cases.


(None,) is a tuple that contains an element, it's not empty and therefore does not evaluate to False in that context.


Because a=(None,) is a tuple containing a single element None

Try again with a=None and you will see there is a different result.

Also try a=() which is the empty tuple. This has a truth value of false


In Python every type can be converted to bool by using the bool() function or the __nonzero__ method.

Examples:

  • Sequences (lists, strings, ...) are converted to False when they are empty.
  • Integers are converted to False when they are equal to 0.
  • You can define this behavior in your own classes by overriding __nonzero__().

[Edit]

In your code, the tuple (None,) is converted using bool() in the if statements. Since it's non-empty, it evaluates to True.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜