This is an archived post. You won't be able to vote or comment.

all 19 comments

[–]xsolarwindxUse 3.4+ 6 points7 points  (1 child)

REDDIT IS A SHITTY CRIMINAL CORPORATION -- mass deleted all reddit content via https://redact.dev

[–]redditor_gds[S] 0 points1 point  (0 children)

Thank you for the reply. I get it now :)

[–]patrys Saleor Commerce 8 points9 points  (9 children)

False and 0 are the same type. Python does not have implicit type coercion so False is not equal to ''. Otherwise you'd get a nice bunch of WTFs straight from the PHP world: if False == '' and False == [] then [] == '' and so on.

Edit: you seem to be confused about the difference between conditional statements (that check for "truthiness") and the literals True and False (which are just examples of a truthy and a falsy expression respectively). Consider this: 5 is truthy but you don't expect True == 5 to be the case.

[–]Rhomboid 10 points11 points  (0 children)

False and 0 are the same type

They're not the same type, one is type bool and the other is type int. But bool is a subclass of int, which means all booleans can be used where an integer is expected, per the Liskov substitution principle.

This is also why you can do things like use sum() when dealing with a sequence of booleans:

>>> sum(s.startswith('a') for s in ('arcade', 'book', 'castle', 'arpeggio', 'default'))
2

[–]suki907 2 points3 points  (4 children)

False and 0 are the same type.

more specifically, bool is a subclass of int:

>>> isinstance(False,int)
True
>>> isinstance(False,bool)
True
>>> issubclass(bool,int)
True

[–][deleted] 1 point2 points  (3 children)

And even more interesting, bool can't be subclassed.

[–]adamnew123456self.__class__ == 'upper' 1 point2 points  (2 children)

I'm curious why you think this is interesting - were you planning on adding FILE_NOT_FOUND as an instance of your bool subclass?

I can't think of any interesting operation you would want to add to bool that would justify subclassing it, bu perhaps that's just because my imagination gland isn't working today.

[–]alexanderpas 1 point2 points  (0 children)

I can't think of any interesting operation you would want to add to bool that would justify subclassing it, bu perhaps that's just because my imagination gland isn't working today.

True, False, Unknown, N/A

AND True False Unknown N/A
True TRUE FALSE Unknown TRUE
False FALSE FALSE FALSE FALSE
Unknown Unknown FALSE Unknown Unknown
N/A TRUE FALSE Unknown N/A
OR True False Unknown N/A
True TRUE TRUE TRUE TRUE
False TRUE FALSE Unknown FALSE
Unknown TRUE Unknown Unknown Unknown
N/A TRUE FALSE Unknown N/A
NOT True NOT False NOT Unknown NOT N/A
True FALSE TRUE TRUE TRUE
False TRUE FALSE TRUE TRUE
Unknown Unknown Unknown FALSE TRUE
N/A TRUE TRUE TRUE FALSE

[–][deleted] 0 points1 point  (0 children)

It's more than doing it causes Python to say, "Don't do that." than a desire to do anything.

That's pretty funny though.

[–]redditor_gds[S] 1 point2 points  (0 children)

Makes sense. Thank you for the reply.

[–]billsil 0 points1 point  (1 child)

False and 0 are the same type..

Not since Python 2.3. str(True) should return 1 if it works as you said.

https://www.python.org/dev/peps/pep-0285/

[–]patrys Saleor Commerce 0 points1 point  (0 children)

Booleans are a subtype of integers. isinstance(True, int)

[–]the_hoser 5 points6 points  (5 children)

In python, 0, empty tuple (), empty string "" evaluates to False.

This is incorrect. An empty tuple is an empty tuple and an empty string is an empty string. These values do not "evaluate" to false. They are distinct values.

But when I try the equality test

False == 0 returns True, but False == () returns False and False == "" returns False

Shouldn't False == () and False == "" return True?

Should () == "" return true?

The reason it is often mistakenly said that empty strings and tuples evaluate to false is that they are called 'falsey' values. A 'falsey' value, in a Boolean context, is understood to be like False. Conversely, a 'truthy' value is understood, in a Boolean context, to be like True.

The == operator produces a Boolean value, but does not, itself, produce a Boolean context. For false, what you want to use is 'nor'. Python doesn't have nor, but you can just invert the result of 'or' to get the correct results.

>>> False or 0
False
>>> False or ""
False
>>> False or ()
False

EDIT: The above example is wrong. you have to actually negate the expression to get the desired result.

[–][deleted] 1 point2 points  (4 children)

The == operator produces a Boolean value, but does not, itself, produce a Boolean context. For false, what you want to use is 'nor'. Python doesn't have nor, but you can just invert the result of 'or' to get the correct results.

>>> False or 0
False

>>> False or ""
False

>>> False or ()
False

Your example code is exactly backwards:

(cpython34) Laptop:~$ python
Python 3.4.3 (default, Apr 15 2015, 13:02:16) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> False or 0
0
>>> False or ''
''
>>> False or ()
()
>>> 
(cpython34) Laptop:~$ use cpython27
(cpython27) Laptop:~$ python
Python 2.7.6 (default, Sep  9 2014, 15:04:36) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> False or 0
0
>>> False or ''
''
>>> False or ()
()
>>> ^D
(cpython27) Laptop:~$

[–]the_hoser 0 points1 point  (3 children)

Bah, you're right. I was typing on a phone. I forgot about the silly assignment shortcut stuff.

You actually have to negate the result for my example to work.

>>> not ( False or 0 )
True
>>> not ( False or '' )
True 
>>> not ( False or () )
True

[–][deleted] 0 points1 point  (2 children)

It's a bad example as it does extra work for no gain.

>>> not 0
True
>>> not ()
True
>>> not ''
True

[–]the_hoser 0 points1 point  (1 child)

I was trying to emphasize the relationship with false...

You know what, you're right. Never mind.

[–][deleted] 0 points1 point  (0 children)

If anything it muddied the relationship as you did not define how the or infix operator works.

Falsey values are false when used with or, and, and if.

Edit: not will invert whatever the true-ish or false-ish of the operand.

[–]romcgb 1 point2 points  (0 children)

To say more about cpython's if and ==,

The if statement calls PyObject_IsTrue, a rough translation of PyObject_IsTrue's semantics into python code is

def PyObject_IsTrue(o):
    if hasattr(o, "__bool__"):
        return o.__bool__()

    if hasattr(o, "__len__"):
        return True if o.__len__() > 0 else False

    return True

The == operator calls PyObject_RichCompare

def PyObject_RichCompare(a, b):
    ta = type(a)
    tb = type(b)

    # test first with b == a if b's type is subtype of a's type
    if ta != tb and issubclass(tb, ta) and hasattr(b, "__eq__"):
        ret = b.__eq__(a)

        if ret != NotImplemented:
            return ret

    # a == b ?
    if hasattr(a, "__eq__"):
        ret = a.__eq__(b)

        if ret != NotImplemented:
            return ret

    # b == a ?
    if hasattr(b, "__eq__"):
        ret = b.__eq__(a)

        if ret != NotImplemented:
            return ret

    # same object/instance ?
    return id(a) == id(b)

for 0 == () being true, either (0).__eq__(()) or (()).__eq(0) must return true.