Python collections.ChainMap

Python学習【365日チャレンジ!】274日目のマスターU(@Udemy11)です。

今日はポッキーの日ですね。

江崎グリコ株式会社が11月11日をポッキー&プリッツの日と定めて、日本記念日協会から認定され、平成11年11月11日にポッキー&プリッツの日がスタートしたそうです。

毎年ポッキーの日だよな〜と思いつつ、ポッキーを食べそこねているので、今年はきっちりポッキーとプリッツを食べておきました。

それでは今日も、Python学習を始めましょう。

昨日の復習

昨日は、辞書型データをリストに入れて便利に扱えるChainMapを学習しました。

updateメソッドのように、複数の辞書型データを一つにまとめるのではなく、複数の辞書型データを個別に保有して、順番を入れ替えたり、値を更新したり、新たな辞書型データを追加したりすることができました。

詳しくは昨日の記事をごらんください。

今日は、ChainMapを継承して条件を付与して値を更新する方法を学習します。

継承クラス

条件をつけて値を更新するには、ChainMapクラスを継承したクラスを定義して条件を付与します。

import collections

a = {'a': 'a', 'num': 10}
b = {'b': 'b', 'c': 'cc'}
c = {'b': 'bbb', 'e': 'e'}

class DeepChainMap(collections.ChainMap):
    def __setitem__(self, key, value):
        for mapping in self.maps:
            if type(mapping[key]) is int and mapping[key] < value:
                mapping[key] = value
            return

m = DeepChainMap(a, b, c)
print(m['num'])
m['num'] = 12
print(m['num'])
print(m.maps)

3行目から5行目で辞書型データを定義しています。

7行目でChainMapを継承したDeepChainMapクラスを作成し、8行目の__setitem__で条件を定義します。

forループでself.mapsを回して、10行目から12行目で、タイプがintで、DeepChainMapに入れたkeyvalueよりも入力されたkeyvalueのほうが大きい場合は、DeepChainMapに入っているkeyvalueを上書きして、条件に合わなければ何もしないというクラスを作成しています。

14行目でDeepChainMapのオブジェクトmを作成して、15行目でDeepChainMapに入っているnumvalueを出力しています。

次に16行目でmnumに、12を代入していますが、このとき、最初に代入されている10より大きいので、値が上書きされます。

17行目で再びnumvalueを出力すると、上書きされた12が出力されます。

最後の行でm.mapsを出力しています。

出力結果

10
12
[{'a': 'a', 'num': 12}, {'b': 'b', 'c': 'cc'}, {'b': 'bbb', 'e': 'e'}]

ちなみに、16行目をm['num'] = 5に変更すると、10以下になるため、値は更新されずに10のままになります。

条件を追加

次に、16行目で指定するkeyが、DeepChainMapに入れた辞書型データのkeyが存在する場合は、valueの値をチェックして値を更新するかそのままにするか判断して、存在しない場合は、辞書型データにkey-valueを追加するコードに変更してみます。

import collections

a = {'a': 'a', 'num': 10}
b = {'b': 'b', 'c': 'cc'}
c = {'b': 'bbb', 'e': 'e'}

class DeepChainMap(collections.ChainMap):
    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                if type(mapping[key]) is int and mapping[key] < value:
                    mapping[key] = value
                return
        self.maps[0][key] = value

m = DeepChainMap(a, b, c)
m['add_num'] = 8
print(m.maps)

出力結果

[{'a': 'a', 'num': 10, 'add_num': 8}, {'b': 'b', 'c': 'cc'}, {'b': 'bbb', 'e': 'e'}]

10行目と14行目を追加して、出力は18行目のm.mapsだけにしています。

17行目でkeyがadd_numにvalueを8にしていますが、add_numがリストに存在しないので、出力結果を見るとmapsの最初の辞書型データにkey-valueの値が追加されているのがわかります。

17行目をm['num'] = 8にすると、値は追加されませんが、m['num'] = 12にすると、最初に入っていたnum12に更新されて出力されます。

まとめ

紹介したコードでいろいろと値を変えてみたり、追加する辞書型データの順番を変えてみたりすると、どのような処理がされているのかつかめてくるので、ぜひいろいろと試してみてください。

これまでも口を酸っぱくして言っていますが(正確には喋っているわけではないので、何度も書いているが正しい?)、いろいろと自分で試すことが大切です。

私も酒井さんの講座を学習しながら、いろいろと普通の人はやらないことをやってエラーが起こったりしてしまいますが、エラーが起こってみないと理解を深めることはできません。

Udemy講師 酒井さん プログラミング Python

コードを書いて、問題なく動いてしまうと、コードを見直すことはしませんが、エラーが起こると、どこが間違っているのかしっかりと確認したり、別のやり方を試したりするので、エラーは起こったほうが学習効果が上がるんじゃないかと感じています。

ぜひ、トライアンドエラーを繰り返して、スキルアップを目指してください。

それでは、明日もGood Python!