Why Python lists and AND / OR operators return "stranger things"?
Published: 2020-02-06 04:33:53

Let's suppose that you're working on a Python project and decide to use the Boolean operators **and** and **or** to compare some lists. After that, you have a heart attack when you get these outputs:

```python
lst1 = [False, False, False]
lst2 = [True, False, True]

print(lst1 and lst2)
>>> [True, False, True]

```

You begin to doubt of your sanity, because you're expecting at least a [False, False, False] list (the output if both lists were compared by indexes) and begin to look for a psychiatrist!!

HEY! Take it easy!!! This is not the way that **and** and **or** work with lists. Let me explain you this secret:

When you compare `lists` with these operators you're not comparing the values but if the `list really has values inside it`. It sounds a bit confusing, so let's see some examples:

Let's create five lists: 2 of them with mixed values, 2 with same values and one empty and then run the **bool()** function to check the Boolean value of them.

```python
lst1 = [True, False, True]
lst2 = [False, True, False]
lst3 = [False, False, False]
lst4 = [True, True, True]
lst5 = []

print(bool(lst1), bool(lst2), bool(lst3), bool(lst4), bool(lst5))
>>>True True True True False

```
We can see that all lists return `True` except the empty one!
Now let's understand how `and` and `or` work:

* `and`: when using it, the operator will evaluate the first element of the comparison. If it's **True** than is returned the second element, if **False** than is returned the first element itself.
```python
#all integers are considered True except zero
x = 1
y = 2
z = False

print(x and y)
>>> 2

print(y and x)
>>> 1

print(z and y)
>>> 

```

* `or`: when using it, the operator will first evaluate the first element of the comparison. If it's **False** than is returned the second element, if **True** than is returned the first element itself.
```python
#all integers are considered True except zero
x = 1
y = 2
z = False

print(x and y)
>>> 1

print(y and x)
>>> 2

print(z and y)
>>> 2
```

Now you can have an idea about what happened in the first code. The first list was evaluated and returned `True`, so the operation returned the second element (second list)!

You must be thinking right now, "Well, just `False` keyword and an empty string are considered False values in Python?"

Answer: **NOOO!!!**
According to the [official reference](https://docs.python.org/3/reference/expressions.html#boolean-operations) are considered `False` values: 

*"`False`, `None`, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets)"* 

The docs also tell us an example that this behavior can be useful:

*"if `s` is a string that should be replaced by a default value if it is empty, the expression `s` or 'foo' yields the desired value. Because not has to create a new value, it returns a boolean value regardless of the type of its argument (for example, not 'foo' produces False rather than ''.)"*

## "What if I want to compare the pairs of elements by their positions?"

To do this, you can use `&` (and) and `|` (or) operators. These operators work bitwise:

```python
lst1 = [False, True, False, True, True]
lst2 = [True, True, False, False, True]

print(lst1 & lst2)
>>> [False, True, False, False, True]

print(lst1 | lst2)
>>> [True, True, False, True, True]
```

Hope these tips can be useful! See ya!