# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# ### 2.1.3 Boolean Expressions
#
# In Python, the booleans are `True` or `False`, also known as logical expressions. The additional keyword `not` can be used to change from one to the other. Compound logical expressions can be created using `and` or `or`, as in:
#
# ```python
# while x > 0 and y <= 1:
#     print(x, y)
# ```
#
# Keep in mind what the logic table says about `and` and `or`:
# ```
# +-------+---------------+        +-------+---------------+
# |  AND  | True   False  |        |  OR   | True   False  |
# +-------+---------------+        +-------+---------------+
# | True  | True   False  |        | True  | True   True   |
# | False | False  False  |        | False | True   False  |
# +-------+---------------+        +-------+---------------+
# also: &&; /\;                    also: ||; \/;
# ```

# **IMPORTANT:**
#
# A logical expression in Python does not return a boolean `True` or `False`, but instead it returns one of the operands. This is in contrast to many other computer languages and shall be explored in the following lines for a bit.
# It is imperative to first understand the boolean nature of various objects:

print(bool(1))
print(bool(-3.14))
print(bool('arghwts'))
print(bool(True))
print(bool([1, 2, 3]))

print(bool(0))
print(bool(0.0))
print(bool(''))
print(bool(False))
print(bool([]))

# Now on to the returned element:

# Let's explore the behaviour of the `and` operator:
print('True and True:  ', (5+1) and -1)
print('True and False: ',    -1 and (1-1))
print('False and True: ', (1-1) and -1)
print('False and False:', (1-1) and '')
print('False and False:',    '' and 0)

# Let's explore the behaviour of the `or` operator:
print('True or True:  ', (5+1) or -1)
print('True or False: ',    -1 or (1-1))
print('False or True: ', (1-1) or -1)
print('False or False:', (1-1) or '')
print('False or False:',    '' or 0)

# Collecting the evidence from above, the returned conditions are best displayed in tables:
#
# ```
#      cond1 and cond2                   cond1 or cond2
# +-------+-------+--------+        +-------+-------+--------+
# | cond1 | cond2 | return |        | cond1 | cond2 | return |
# +-------+-------+--------+        +-------+-------+--------+
# | True  | True  | cond2  |        | True  | True  | cond1  |
# | True  | False | cond2  |        | True  | False | cond1  |
# | False | True  | cond1  |        | False | True  | cond2  |
# | False | False | cond1  |        | False | False | cond2  |
# +-------+-------+--------+        +-------+-------+--------+
#
# ```

# It remains to be tested what a longer sequence produces. Therefore, three conditions will be combined:

# +
# Let's make sense of the previous and try a chained structure:
print('T and T and T:', 3 and 4 and 5)

print('T and T and F:', 3 and 4 and 0)
print('T and F and T:', 3 and 0 and 5)
print('F and T and T:', 0 and 4 and 5)

print('T and F and F:', 3 and 0 and '')
print('F and T and F:', 0 and 4 and '')

print('F and F and F:', 0 and '' and [])

# +
# Let's make sense of the previous or try a chained structure:
print('T or T or T:', 3 or 4 or 5)

print('T or T or F:', 3 or 4 or 0)
print('T or F or T:', 3 or 0 or 5)
print('F or T or T:', 0 or 4 or 5)

print('T or F or F:', 3 or 0 or '')
print('F or T or F:', 0 or 4 or '')

print('F or F or F:', 0 or '' or [])
# -

# Concluding, the operators' return works like this:
#
# **AND**: Return the first condition that evaluates to `False` or in the case of all `True`, return the last condition in the entire expression.
#
# **OR**: Return the first condition that evaluates to `True` or in the case of all `False`, return the last condition in the entire expression.
#
# Quoting from the [Python3 documentation](https://docs.python.org/3/library/stdtypes.html#index-4):
# >These are the Boolean operations, ordered by ascending priority:
# >
# >\[`or`\] is a short-circuit operator, so it only evaluates the second argument if the first one is false.
# >
# >\[`and`\] is a short-circuit operator, so it only evaluates the second argument if the first one is true.
# >
# >`not` has a lower priority than non-Boolean operators, so not a == b is interpreted as not (a == b), and a == not b is a syntax error.

StarcoderdataJupyterScriptsDedupFiltered