CTC 教育サービス
[IT研修]注目キーワード Python Power Platform 最新技術動向 生成AI Docker Kubernetes
こんにちは、吉政創成 菱沼です。
今回も「きれいなPythonプログラミング(マイナビ出版)」という書籍を利用して学習します。
前回はPythonのインデックスに対する他言語出身者との感覚の違いと、誤用の多い構文の節その1ループ処理を簡単にするenumerate()関数について学びました。
今回は前回に続いて誤用の多い構文の節を学びます。with文のすすめと、恒等演算子is/統合演算子==の違いやNoneとの関係です。
では早速引用文から。
------------------------------------
P.97 6.3.2 open()とclose()ではなくwith文を使う
open()関数は、ファイルを読み書きするためのメソッドを含んだファイルオブジェクトを返します。読み書きの終了後にファイルオブジェクトのclose()メソッドを呼び出せば、他のプログラムがファイルを読み書きできるようになります。これらの関数は個別に使う事もできますが、そのようなことをしても意味がありません。
(中略)
with文を使えば、with文のブロックを抜ける時に自動的にclose()を呼び出すことができます。
------------------------------------
Pythonでファイルの読み書きをしたい/データを表示したい場合、ファイルをまずは開くという作業が必要になりますが、その際に使用されるのがopen()関数です。
変数名 = open("ファイル名")
一方、プログラムを終了する際には、open()で開いたファイルを閉じる必要がありますが、その際に使用されるメソッドがclose()です。
変数名.close()
close()を忘れてもプログラムが終了すると同時に自動的に閉じられることは閉じられますが、close()でファイルを閉じておかないと、
といった問題が起きる可能性があります。そのため、open()とclose()はセットで使うのが基本になります。
ただ、Pythonの場合、with文を使うことができます。
with文は「コンテキストマネージャ」と呼ばれる仕組みを使うための構文で、「処理の準備」と「終わった後の片づけ」の処理を自動で行ってくれるものになります。内部の処理を終えると同時に自動で閉じてくれるため、close()を書く必要がなく、途中でエラーが発生しても、問題なくファイルを確実に閉じるなどの後処理をしてくれます。
with文は、今回のようなファイル操作で使われる以外に、例えばデータベースやネットワークへの接続、スレッドやプロセスのロック処理といった場面でも使われるそうです。
基本的な書式は次の通り。
with コンテキストマネージャ as 変数名:
処理内容
ファイル操作をするのであれば次のように書かれます。
with open('ファイル名', 'モード') as f:
処理内容
モードに入れる値は次のようなものがあります。
r :読みこみ
w :書き込み(上書き)
a :追記(append)
b :バイナリ(binary)
※ r や w と組み合わせて「rb」「wb」のように使います。
r+ :読み書き両方
まずは引用文から。
------------------------------------
P.98 6.3.3 ==ではなくisを使ってNoneと比較する
統合演算子==は2つのオブジェクトの値を比較するのに対し、恒等演算子isは2つのオブジェクトの同一性を比較します。(中略)オブジェクトが2つあったとして、それらは同じ値を格納することができますが、値が同じだからといって同じオブジェクトとは限りません。ただし、値をNoneと比較する場合は、基本的に==ではなくisを使います。
場合によっては、spam == Noneという式がTrueと評価されることもあります。これは17章で詳しく説明する==演算子のオーバーロードによるものです。しかし、spam is Noneの場合は、spam変数の値が文字通りNone(何もない)であるかどうかをチェックします。NoneはNoneTypeデータ型の唯一の値であるため、PythonプログラムにはNone
オブジェクトが1つだけ存在します。変数がNoneに設定されている場合、is Noneとの比較は常にTrueと評価されます。
------------------------------------
まず==とisの整理から...。
例えば、
a = [1, 2, 3]
b = [1, 2, 3]
という2つのリストがあったとき、中身の値を比較する(==)と、
a == b
True
となります。これは==がリストの中身を比較しているためです。
一方、恒等演算子であるisで比較した場合、
a is b
False
という結果になります。
isは、リストの中身を比較するのではなく、同じ箱そのものか比較しているためです。aとbというリストは中身の値は同じでも、別々の「箱」なので、違うものだよ!ということになります。
例えばこれが、リストbの中身がリストaだったという状態だったのなら、Trueが返されます。
a = [1, 2, 3]
b = a
a is b
True
という前提を理解した上で、Noneの比較にはisを使うという件です。
None は Python 内で「唯一一個しか存在しない特別なオブジェクト」だそうです。
Noneは「値が存在しない」「何も返さない」「初期値がない」「空でもゼロでも False でもない無」という特殊な状態を表すために用意されたものだからこそ、1つだけと決められているそうです。
(複数のNoneがあると、"どの None と比べて True なの?"と、混乱状態になってしまうためです。)
つまり、、、Noneを比較するときにisを使えば、その変数が唯一のNoneを指しているのか、誰にも改変されていない確実で安全な比較になっているのかが保証されるということになります。
例えば、
a = None
b = None
c = None
という3つのオブジェクトがあったとき、この3つのオブジェクトが指し示すNoneは同じNone(Pythonの唯一のNone)です。
なので、
a is b
b is None
という比較は双方、Trueという結果になります。
==を使っても、値の比較としては同じなので、Trueが返されますが、==の場合、クラスの中身によっては結果が捻じ曲げられてしまう(オーバーロード)可能性があります。
例えばこちら、書籍のサンプルコードです。
class SomeClass:
def __eq__(self, other):
if other is None:
return True
spam = SomeClass()
spam == None
True
spam is None
False
SomeClassでは、Noneと比べられたら必ずTrueを返すという独自ルールが作られていますので、spam == NoneはTrueになってしまいます。
一方、isは箱そのもの(オブジェクトの同一性)と比較をするので、Falseという正しい結果が返されています。
というわけで、Noneの比較は正しい結果を返せるisを使いましょう!ということです。
最後に注意点を引用しておきます。
------------------------------------
P.99
値がTrueやFalseの場合はis演算子を使ってはいけません。統合演算子==を使って、spam == Trueやspam == Falseのように比較しましょう。演算子とブール値を完全に省いて、if spam == True:やif spam == False:ではなく、if spam:やif not spam:のようなコードを書くのがより一般的です。
------------------------------------
True / False は「値」なので、同一性を比較するisでは目的が合わないため、==で比較しましょうということですね。
それでは今回はこちらで終了です。
今回もお付き合いいただきありがとうございました。
[IT研修]注目キーワード Python Power Platform 最新技術動向 生成AI Docker Kubernetes