==は通常__eq__を介して、2つのオブジェクトが値として等価であるかを判定します。一方、isは2つの参照がメモリ上のまったく同一のオブジェクトを指しているかどうかを判定します。本番環境のコードにおいて、isは通常、value is Noneのようなシングルトンの検証、同一性が真に重要な場合のvalue is True、または番兵オブジェクトのチェックに限定して使用すべきです。小さな整数のキャッシュや文字列のインターン化のような実装の詳細に依存してはいけません。これらはコード例ではisが機能しているように見えても、セマンティクスとしては誤った選択になります。
クロージャとは、外側の関数がリターンした後も、その外側のスコープにある変数へのアクセスを保持し続ける関数のことです。これはデコレータやコールバックファクトリ、設定済み関数を作成する際に役立ちます。遅延バインディングとは、自由変数が関数の作成時ではなく、内部関数が呼び出された時点で検索・参照される動作を指します。そのため、ループ内で作成されたラムダ式は、すべてループの最終値を参照してしまうことがあります。これを回避するには、例えば lambda i=i: i のようにデフォルト引数を使って現在の値をキャプチャするか、小さなファクトリ関数を使用します。
callbacks = []
for i in range(3):
callbacks.append(lambda: i)
print([callback() for callback in callbacks]) # [2, 2, 2]
callbacks = []
for i in range(3):
callbacks.append(lambda i=i: i)
print([callback() for callback in callbacks]) # [0, 1, 2]
from contextlib import contextmanager
with open("data.txt", encoding="utf-8") as file:
data = file.read()
@contextmanager
def temporary_setting():
print("enter")
try:
yield
finally:
print("exit")