How do "and" and "or" work when combined in one statement?

Question:

For some reason this function confused me:

def protocol(port):
    return port == "443" and "https://" or "http://"

Can somebody explain the order of what’s happening behind the scenes to make this work the way it does.

I understood it as this until I tried it:

Either A)

def protocol(port):
    if port == "443":
        if bool("https://"):
            return True
    elif bool("http://"):
        return True
    return False

Or B)

def protocol(port):
    if port == "443":
        return True + "https://"
    else:
        return True + "http://"

Is this some sort of special case in Python, or am I completely misunderstanding how statements work?

Asked By: orokusaki

||

Answers:

and returns the right operand if the left is true. or returns the right operand if the left is false. Otherwise they both return the left operand. They are said to coalesce.

It’s an old-ish idiom; inserting parentheses to show priority,

(port == "443" and "https://") or "http://"

x and y returns y if x is truish, x if x is falsish; a or b, vice versa, returns a if it’s truish, otherwise b.

So if port == "443" is true, this returns the RHS of the and, i.e., "https://". Otherwise, the and is false, so the or gets into play and returns `”http://”, its RHS.

In modern Python, a better way to do translate this old-ish idiom is:

"https://" if port == "443" else "http://"
Answered By: Alex Martelli

This is an ugly hack that is not recommended. It works because of the short-circuiting behaviour of and and or and that they return the one of their arguments rather than a boolean value. Using this technique gives a risk of introducing hard-to-find bugs, so don’t use it in new code.

Here’s an example of how the and/or idiom can give an unexpected result:

>>> foo = 'foobar'
>>> bar = 'foobar'
>>> x = 0
>>> y = 1
>>> (foo == bar) and x or y   # Will this return the value of x if (foo == bar)?
1

Prefer instead the newer notation:

return "https://" if port == "443" else "http://"
Answered By: Mark Byers

You may want to read up on the “and / or trick” of Python in this article The Peculiar Nature of And and Or in Python. It’s a bit like the IIF() in VBA or VB, or ?: in C-style languages.

Answered By: Abel

This construction works because it ‘unfolds’ to the following code:

a and b –>

if a:
  return b
else:
  return a

a or b –>

if a:
  return a
else:
  return b
Answered By: Yaroslav

C and X or Y is the long-running early attempt by Python users to proxy for C ? X : Y

For the most part it works, except if X is False — this has led to many bugs in Python code, so in the Python FAQ, you’ll find the more correct solution being (C and [X] or [Y])[0] because a list with a single element, regardless of its evaluated Boolean value, is always True! For example: [None] is True but None isn’t. The OP’s example above works because the string representing X is not empty.

However, all this changed in Python 2.5, when the ternary or conditional operator was added to the language, allowing you to use the cleaner X if C else Y as stated in other posts here. If you see code using the older format, it’s because the user has been a long time Python programmer who hasn’t adopted the new syntax yet, they cut-n-paste other old code, or their employer is still using 2.4.x (or earlier releases), etc.

Answered By: wescpy

With all the good answers, I found these statements help me remember this better and fit how my brain works (and hopefully for for some more out there) :

  • “and” returns the first False item (e.g., None, “”, [], (), {}, 0) or the last item if none (e.g. no False found)

  • “or” returns the first True item or the last item (e.g. no True found)**

In summary:

  • they all return the first item that decides the outcome of the statement. (In the worst case, the last item in the sequence)

Note this rule also applies to a chained all “and” or all “or” statement

Answered By: Zhenhua