[Python入門]オブジェクトの同一性、比較、文字列表現:Python入門(2/2 ページ)
Pythonのオブジェクトの同一性と、is演算子や==演算子による比較の違い、str関数とrepr関数で得られる文字列表現の違いなどについて取り上げる。
str関数とrepr関数
簡単にいってしまうと、これら2つの関数には次のような目的の違いがある。
- str関数:オブジェクトの「非公式な文字列表現」を得る
- repr関数:オブジェクトの「公式な文字列表現」を得る
ここでいう「非公式」な文字列表現とは、「人が読める簡潔な表現」を意味している。対して、「公式な文字列表現」とは、「Pythonにとって意味のある表現」を意味している。
ここでいう「Pythonにとって意味のある表現」とは次のような意味合いだ。
- その文字列表現からもともとのオブジェクトを復元できる
- 復元できなければ山かっこ「<>」に囲まれた中に、何らかの意味ある情報を含める
このうちの前者が文字列'Hello'をstr関数とrepr関数で文字列化したときの差につながっている。2つの関数の戻り値がどうなっているのかを、より明確にするために少し試してみよう。
まず以下のコードを実行する。
str('Hello')
この実行結果は次のようになる。
次に、以下のコードを実行する。
repr('Hello')
こちらの実行結果は次のようになる。
お分かりだろうか。こちらはシングルクオートで囲まれた「'Hello'」がさらにダブルクオート「"」で囲まれて「"'Hello'"」となっている。
ここでPythonには組み込みのeval関数がある。これは引数に受け取った文字列の値を「Pythonの式」として評価して、その結果を戻り値とするものだ。
eval関数
eval(expression)
expressionの値を「Pythonの式」として評価して、その結果を戻り値とする。expressionの評価時には、その評価で使用する名前空間として辞書を渡せるが、ここでは省略する。
パラメーター | 説明 |
---|---|
expression | Pythonの式として評価する文字列 |
eval関数のパラメーター |
この関数を使って、「オブジェクトを復元」してみよう。まずは「オブジェクトを復元する」ことを目的としたrepr関数を使ってみよう。
hello = repr('Hello')
print(len(hello))
eval(hello)
実行結果は次のようになる。
ご覧のように文字数が「7」であることが示された後で、最後に「'Hello'」と表示され、文字列'Hello'が復元されたことが分かる。では、次にstr関数を使って同じことをしてみよう。
hello = str('Hello')
print(len(hello))
eval(hello)
実行結果は次のようになる。
上の画像に示した通り、これはエラー(NameError例外)となる。と同時に、文字列の長さが「5」であることにも注目しよう。
なぜこのような違いが出たかを考えてみよう。まず、repr関数が返した値は「"'Hello'"」となっていた。外側のダブルクオートは「'Hello'」を囲んでいる。つまり、文字列の値そのものは「'Hello'」である。これをeval関数に渡すと、「'Hello'」という文字列として評価される。そのため、これはエラーとはならない。
これに対して、str関数が返した値は「'Hello'」であり、その値は「Hello」という「5」文字の文字列である。つまり、eval関数にはシングルクオートで囲まれていない「Hello」が渡されることになる。これをPythonが評価しようとして、「Hello」という「名前」はないよ、というエラーになったということだ。
これがstr関数とrepr関数の差といえる。前者は人が読みやすい表現(「Hello」だけ)となり、後者はPythonにとって意味のある表現(復元可能な文字列表現)となっている(ただし、クオート文字が二重になり、人が見ると冗長に感じられるかもしれない)。ただし、今見たのは文字列を例に取ったものであり、他のオブジェクトでは同じものが得られることもあれば、両者の結果がもっと大きく異なることもある。
例えば、先ほどリストや整数をstr関数やrepr関数に渡したときに、その結果が同じになった。これは、シングルクオートで囲んだ「'[1, 2, 3]'」などはeval関数に渡しても、リストとしてきちんと評価できることからと考えられる。と、同時に「'[1, 2, 3]'」というのは人の目にも分かりやすい表現となっている。
このように、repr関数はまず元のオブジェクトを復元できることを目的とした文字列表現を作成することを念頭に置いている。ただし、そうでない場合には、プログラムをデバッグするときなどに有用な情報を山かっこ「<>」に囲んだものを返すべきとしている。
例えば、関数を定義して、その公式な文字列表現を得てみよう。
def somefunc():
print('some func')
repr(somefunc)
この場合の実行結果は次のようになる。
山かっこ「<>」に囲まれて、その型(function)と関数名(somefunc)、最後にそのアイデンティティーが表示された。これが、オブジェクトを復元できないが、役に立つ情報の例だ。興味のある人は、いろいろなオブジェクトをstr関数やrepr関数で文字列化してみよう。
なお、str関数にオブジェクトを渡して、その非公式な文字列表現を得ようとしたときに、それが用意されていないと、最終的にはその公式な文字列表現が返される。そのため、非公式な文字列表現と公式な文字列表現が同じ(同じで十分)なこともある。この仕組みについては、後続の回で取り上げる予定だ。
まとめ
今回はオブジェクトのアイデンティティーと、その比較、文字列表現について見た。次回は、これまでに出てきた演算子を含めて、Pythonの演算子についてざっくりとまとめる。
今回のまとめ:オブジェクトの同一性、比較、文字列表現
- オブジェクトはそのアドレス(のようなもの)を表すアイデンティティーを持つ
- オブジェクトのアイデンティティーは、それが作成された後、削除されるまで変わることはない
- アイデンティティーを調べるにはid関数が使える
- オブジェクトを比較するには、同一性と等価性に注意する必要がある
- 同一性の比較とは「オブジェクトが同じアイデンティティーを持つかどうか」を調べることで、is演算子/is not演算子を使える
- 等価性の比較とは「オブジェクトが同じ値かどうか」を調べることで、==演算子/!=演算子を使える
- 等価性の比較を行う際に、デフォルトでは同一性の比較が行われるが、Pythonの組み込み型ではこのデフォルトの動作を書き換えて、アイデンティティーが異なるオブジェクト同士でもその値が等しいかが適切に比較されるようになっている
- オブジェクトの文字列表現を得るには、str関数とrepr関数が使える
- str関数はオブジェクトの「非公式な文字列表現」を返す
- repr関数はオブジェクトの「公式な文字列表現」を返す
- 「非公式な文字列表現」とはオブジェクトを「人が読みやすい簡潔」な表現にしたもの
- 「公式な文字列表現」とはオブジェクトを「Pythonにとって意味のある」表現にしたもの
- 「Pythonにとって意味のある」表現とは、その表現から元のオブジェクトを復元できるか、デバッグなどで役に立つ情報を含んでいること
「Python入門」
Copyright© Digital Advantage Corp. All Rights Reserved.