Question: I am confused as to when I should use Boolean vs bitwise operators

* `and` vs `&`
* `or` vs `|`

Could someone enlighten me as to when do i use each and when will using one over the other affect my results?

Answer: 
The general rule is to use the appropriate operator for the existing operands. Use ***boolean*** (logical) operators with ***boolean*** operands, and ***bitwise*** operators with (wider) ***integral*** operands (note: *False* is equivalent to ***0***, and *True* to ***1***). The only "tricky" scenario is applying boolean operators to non boolean operands.   
Let's take a simple example, as described in [[SO]: Python - Differences between 'and' and '&'](https://stackoverflow.com/questions/50446174/python-differences-between-and-and):   
`5 & 7` *vs.* `5 and 7`.

For the *bitwise **and*** (**&**), things are pretty straightforward:

> 
> 
> ```py
> 5     = 0b101
> 7     = 0b111
> -----------------
> 5 & 7 = 0b101 = 5
> 
> ```
> 
> 

For the *logical **and***, here's what [[Python.Docs]: Boolean operations](https://docs.python.org/3/reference/expressions.html#boolean-operations) states (**emphasis** is mine):

> 
> (Note that neither [and](https://docs.python.org/3/reference/expressions.html#and) nor [or](https://docs.python.org/3/reference/expressions.html#or) restrict the value and type they return to *False* and *True*, but rather **return the last evaluated argument**.
> 
> 
> 

**Example**:

> 
> 
> ```py
> >>> 5 and 7
> 7
> >>> 7 and 5
> 5
> 
> ```
> 
> 

Of course, the same applies for ***|*** *vs.* *or*.
**Boolean 'and' vs. Bitwise '&':**

Pseudo-code/Python helped me understand the difference between these:

```
def boolAnd(A, B):
    # boolean 'and' returns either A or B
    if A == False:
        return A
    else:
        return B

def bitwiseAnd(A , B):
    # binary representation (e.g. 9 is '1001', 1 is '0001', etc.)

    binA = binary(A)
    binB = binary(B)

    # perform boolean 'and' on each pair of binaries in (A, B)
    # then return the result:
    # equivalent to: return ''.join([x*y for (x,y) in zip(binA, binB)])

    # assuming binA and binB are the same length
    result = []
    for i in range(len(binA)):
      compar = boolAnd(binA[i], binB[i]) 
      result.append(compar)

    # we want to return a string of 1s and 0s, not a list

    return ''.join(result)

```