前提
pythonのバージョンは3.10.0で動作を確認しています。
「if文って何?」「どうやって使うんだっけ?」という方は以下の記事をご覧ください。
結論
and演算子と&演算子では、演算対象が異なります。
and演算子は、真偽として評価可能なすべての値、オブジェクトに対して使えます。
&演算子は、整数と特定のオブジェクトにしか使えません。
個人的には、if文で真偽判定として使うなら、andを使うべきだと思います。
公式ドキュメントでの定義
公式サイトによる、andと&の説明を見てみましょう。
and演算子
まずはandです。
式 x and y は、まず x を評価します; x が偽なら x の値を返します; それ以外の場合には、 y の値を評価し、その結果を返します。
https://docs.python.org/ja/3/reference/expressions.html#boolean-operations
「TrueかFalseを返す」のではなく、「xかyを返す」というところがよく誤解されているので注意ですね。
評価して偽になるものの例としては、bool型のFalse、int型の0、list型の[]などがあります。
&演算子
次に&についても見てみましょう。こちらはまだ、この記事執筆時点では日本語訳されていないようです。
The & operator yields the bitwise AND of its arguments, which must be integers or one of them must be a custom object overriding __and__() or __rand__() special methods.
https://docs.python.org/ja/3/reference/expressions.html#binary-bitwise-operations
要約すると、「&演算子は引数のビット単位での論理積を返す。引数は整数か、__and__()メソッドまたは__rand__()メソッドをオーバーライドしたオブジェクトでなければならない」です。
&演算子は、基本的には整数に対して使用します。
どっちを使うべき?
これは場合によるので一概には言えませんが、個人的にはif文の中ではand演算子を使った方がミスが減り、読みやすくなると思います。
bool型の値のみを扱う場合はどちらでも同じ結果になるのですが、Pythonの言語仕様上、bool値以外の値がくる可能性を排除できません。
if文の中で&演算子を使うということは、if文の中で計算を行うということですが、それだとコードが読みにくくなります。
REPLでの以下の例を見てみましょう。
>>> p1 = 1
>>> p2 = 2
>>> if p1 and p2:
... print("Yes")
...
Yes
>>> if p1 & p2:
... print("Yes")
...
>>>
何が起こっているのでしょうか。
p1 and p2の方では、p1(=1)を評価して真になるので、式の評価結果はp1(=1)となります。1は真とみなされるので、Yesが出力されます。
p1 & p2では、整数「1」と整数「2」のビットごとの論理積を計算しています。計算結果は0になります。0は偽とみなされるため、Yesは出力されません。
私の経験上、if文の中で「p1 and p2」「p1 & p2」と書く場合は、「「p1が真であり、かつ、p2が真である」場合に真として評価される」ことを期待して書くことが多いです。無意識にp1とp2がbool型であると想定してしまっているのです。そう意図して「p1 & p2」と書いた場合(そう意図してはいけないですが…)プログラマの意図しない動作をしていることになります。
&を使う例として奇数判定がありますが、こちらも%演算子を使う方が分かりやすいと思います。奇数の定義が「2で割った余りが1の数」であり、それをそのままコーディングしているためです。
>>> # 以下はどちらも同じ結果になる
>>> x = 7
>>> if x % 2 == 1:
... print("xは奇数です")
...
xは奇数です
>>> if x & 1:
... print("xは奇数です")
...
xは奇数です
>>>
あくまで個人的な意見なので、反論もあるかと思いますが、一つの意見としてご参考にしていただければと思います。もちろん、明らかな間違いがある場合はコメントで教えていただけると大変助かります。