🙄

【Python】dict.copy()したのに中身が上書きされてしまった!

に公開

概要

SlackのAPIを利用して2種類の情報をそれぞれ別のチャンネルに通知するためのプログラムで両方のチャンネルに同じ情報が出てしまった。

通知したい内容の部分以外はSlackAPIのためのデータの構成は同一であるため、以下のように記載。

バージョン情報

今回の知見にバージョンはあまり関係はないが、念のため。

  • Python3.9
  • AWS Lambda

スクリプト

default = {
    'username': '',
    'blocks': [
        {
            'type': 'section',
	    'text': {
	        'type': 'mrkdwn',
		# 'text': '通知したい内容'
	    }
	}
    ]
}

slack1 = default.copy()
slack1['blocks'][0]['text']['text'] = 'hogehoge'

slack2 = default.copy()
slack2['blocks'][0]['text']['text'] = 'fugafuga'

この後、slack1, slack2を使用してrequestしたところ、両チャンネルにfugafugaと通知されてしまった。
ログにオブジェクトIDを出力しても、問題無く別のIDが出力されるため原因が分からず。

logger.info(id(default)) # XXXXXXXXXX0
logger.info(id(slack1))  # XXXXXXXXXX1
logger.info(id(slack2))  # XXXXXXXXXX2

結論

今回のスクリプトではdict内にlistが含まれており、dictは別のオブジェクトとして存在したものの、dict内のlistが同じものであったことが原因だった。

copy()が浅いコピーであったために、発生。
deepcopy()にてdictを再帰的にコピーすることで解決。

import copy

default = {省略}

slack1 = copy.deepcopy(default)
slack1['blocks'][0]['text']['text'] = 'hogehoge'

slack2 = copy.deepcopy(default)
slack2['blocks'][0]['text']['text'] = 'fugafuga'

参照:Python公式ドキュメント | copy --- 浅いコピーおよび深いコピー操作

Discussion