NoSingleLogicAnd
Observed

NoSingleLogicAnd
Incorrect

& is only a bitwise AND

Correct

& for boolean operands is a logical AND

Correction
Here is what's right.

While & can be a bitwise AND, & can also be used as a logical AND between bool operands. That’s because in Python, booleans are actually integers: False is 0, and True is 1.

a = False
b = True
c = a and b  # logical AND (short-circuit)
a = False
b = True
c = a & b  # logical AND
a = 1
b = 3
c = a & b  # bitwise AND

Note that & is an eager logical AND. “Eager” means it always evaluates both operands before producing a value. On the other hand, and is a short-circuit logical AND. It first evaluates the left operand; if that is False, then it does not evaluate the right operand and simply produces False. This can be very useful for conditions like the following, because it prevents ZeroDivisionError that would have been raised if the right operand had to be evaluated:

if lst != [] and sum(lst) / len(lst) > 42:
    ...

Symptoms
How do you know your students might have this misconception?

If students claim that & is a bitwise AND, and and is a logical AND, then they probably also believe that & cannot work with bool operands.

Value
How can you build on this misconception?

It can be instructive to think about a situation where the difference between & and and is observable. Consider the following example:

def f():
    print("hi")
    return False

Evaluating f() and f() will print “hi” only once, because the second call to f() is not evaluated due to short-circuiting. On the other hand, evaluating f() & f() will print “hi” twice, because both calls to f() are evaluated regardless of the result of the first call.