『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

ミュータブルとイミュータブル

【Python】ミュータブルとイミュータブル

Python にはミュータブルなオブジェクトとイミュータブルなオブジェクトがあります。リスト、ディクショナリ、set は要素を入れ替えたり削除したりできるので、ミュータブルなオブジェクトです。数値、文字列、タプルなどは一度定義してしまうと、自身を作り変えることができないのでイミュータブルなオブジェクトに分類されます。実際のコードで確認してみましょう。まずはリストの要素を置き換えてみます。

# PYTHON_MUTABLE

# In[1]

# 芳香族化合物のリスト
aroma = ["トルエン", "フェノール", "アニソール"]

# フェノールをニトロベンゼンに置き換えます
aroma[1] = "ニトロベンゼン"

print(aroma)
# ['トルエン', 'ニトロベンゼン', 'アニソール']

次はタプルの要素を置き換えてみます。

# In[2]

# 芳香族化合物のリスト
aroma = ("トルエン", "フェノール", "アニソール")

# フェノールをニトロベンゼンに置き換えます
aroma[1] = "ニトロベンゼン"

print(aroma)

'''
TypeError
 Traceback (most recent call last)
  in ()
       3 
       4 # フェノールをニトロベンゼンに置き換えます
 ----> 5 aroma[1] = "ニトロベンゼン"
       6 
       7 aroma

 TypeError: 'tuple' object does not support item assignment
'''

タプルの要素を別の要素に置き換えようとするとエラーが発生しました。tuple object は item(要素)の assignment(割り当て)ができないと警告されています。リストには並び順を変更したり、要素を追加・削除するようなメソッドが豊富に用意されていますが、タプルにはそのようなメソッドがありません。しかし、タプルと同じくイミュータブルなオブジェクトである文字列になると少し話がややこしくなってきます。たとえば次のようなメソッドを使った例です。

# In[3]

#ベンゾフェノンをベンゾニトリルに変えます
x = "benzophenone".replace("phenone","nitrile")

print(x)
# 'benzonitrile'

replace は文字列に備わる「文字を置き換える」メソッドです。上のサンプルコードでは benzophenone の phenone を nitrile に置き換えて、benzonitrile という単語に作り変えてしまっています。こんなことができてしまうのに、どうして文字列はイミュータブルであるといえるのでしょうか? 実はこのメソッドは文字列そのものを変更しているわけではなく、もとの文字列とは別の新しい文字列(コピー)を作って返しているのです。この仕組みは次のように文字列をいったん変数に格納しておくと理解できます。

# In[4]

#ベンゾフェノンをベンゾニトリルに変えます
x = "benzophenone"
x.replace("phenone", "nitrile")

print(x)
# 'benzophenone'

x.replace(“phenone”,”nitrile”) によって新しい文字列を生成していますが、変数 x の参照先のオブジェクトが変更されているわけではないので、最後の x というコードでは、もとの文字列 benzophenone を表示するだけです。しかし、このコードをほんの少し変えて、次のようにしてみると、また結果は違ってきます。

# In[5]

#ベンゾフェノンをベンゾニトリルに変えます
x = "benzophenone"
x = x.replace("phenone","nitrile")

print(x)
# 'benzonitrile'

今度は benzonitrile という作り変えられたほうの文字列が返ってきました。これは x という変数が作り変えられたほうの文字列を参照するようにしているからです。細かい話のように思えますが、データの所在を常に頭の中で追跡する癖をつけておかないと、複雑なプログラムを作って不具合が生じたときに対処が難しくなります。

リストのようなミュータブルなオブジェクトが、並び替えや要素の追加などによって自身を書き換える操作のことを「破壊的操作」とよぶことがあります。リストに備わる sortメソッドや、appendメソッドも破壊的操作を伴います (もちろん、ミュータブルなオブジェクトのメソッドすべてが破壊的操作を伴うわけではありません)。一方で、イミュータブルなオブジェクトには破壊的操作を伴うメソッドは1つもありません。

コメント

  1. あとりえこばと より:

    【プログラミング日記】WP Code Highlight.js という、サイトにコードを表示させるプラグインを導入しました。しかし、いざこのプラグインを使い始めてみると、次々と問題が発生して、その対応に追われることになったのです。

    最初の問題はコードをハイライトしてくれないってことです。ハイライトというのは、コードの記号を種類別に色分けしてプログラマーを助けてくれる機能のことです。でもハイライトされない。WP Code “Highlight”.js なのにハイライトされない。泣きたくなりましたよ、本当に。原因はもともとサイトの CSS(文字や段落などのデザインを決めるコード)に書かれていた、「コードはこういうふうに表示しようね」という箇所と競合していたことでした。それをばっさり切り取ると、ハイライトされたコードが現れました。ようやくこれで解決かと思っていたら、よく見ると何かがおかしい。たとえば、こんな感じ。
    プラグイン WP Code Highlight.js
    ハイライトされているのもあれば、されていないところもあって、ちぐはぐに …
    思わず「何でやねん!」(← 関西育ち)と叫びましたよ。
    もちろん本当に叫んだのではなく、心の中で叫んだのです。
    家族が不審に思うといけないから。

    それはともかく、原因を探っていると、コードを埋め込むときに使うコード(ややこしい)の書き方が問題だったようです。プラグインの説明によると、
    「特に言語を指定しなくても、こっちで自動的に判断するよ」
    とあったので、それを真に受けて言語指定を怠っていたのです …
    「できてないじゃん。自動判断できてないじゃん」
     ちょっと切れそうになりながらもマニュアルを見て言語 (Python) をきっちり指定しておくことにしましたが…

    「 … 全然直らない。WP Code Highlight.js、あかんわ」
     もはやこれまでかと思いつつ、ネットで情報を集めてみると、
    「 class=”language-Python” と指定しよう」
    と書いてありました。な、な、なんですと~!? マニュアルには
    「 class=”Python” と指定しましょう」
    とあったけど!?
    「おのれ~。もう2度と英語のマニュアルなんて信用するものか~」
    という意味不明な逆恨みをしつつ、全ての記事を書き直している最中なのです。単調で疲れる作業です。貴重な時間を返してほしい … とにかく、そんなわけで、この単純労働が終わったら新しい記事を書くので、しばらくお待ちください。