Diary over Finite Fields

515ひかるが書き溜めたメモとコラムと雑記

自分なりに整理してみた: Pythonの mutable オブジェクトの罠

Python の話

最近Pythonの「不可解な挙動」として類似のツイートを2つ見かけた。なので別に反論したいわけでもないのだが、ここに書いておこうと思う。

Python 3.6.2 (default, Jul 20 2017, 03:52:27)
[GCC 7.1.1 20170630] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 1
>>> b = a
>>> a += 1
>>> a
2
>>> b
1
>>> assert a != b
>>> c = [1]
>>> d = c
>>> c.append(2)
>>> c
[1, 2]
>>> d
[1, 2]
>>> assert c != d
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

上の方のコードは整数 1 を変数 a に代入し、変数 ba を代入。その後に a += 1 すると、 a のみが変更され b は変更されない。

一方、リストのほうは c というリストに d を代入したあとで c を変更したが、同時に d にも変更がなされている。

挙動の理由

なぜこのようなことが起きるのか。

まず、Pythonにおいて変数への代入はオブジェクトへの参照である。そのため、数値だろうがリストだろうが次が成り立つ:

>>> a = 1
>>> b = a
>>> a is b
True
>>> c = [1]
>>> d = c
>>> c is d
True

一方で、数値は immutable であるから、変数 a に再代入をするとき a にはもとの a と異なるオブジェクトへの参照がわたされる。したがって、次のようなことが起こる。

>>> a += 1
>>> a is b
False

しかし、リストの append メソッドは異なる。append はリスト c を自体を変更し、オブジェクトの参照先は d と同一のままである。つまり以下の挙動を示す。

>>> c = [1]
>>> d = c
>>> c.append(2)
>>> c is d
True

たとえば append ではなく、c にリストの足し算を行うと異なる挙動を示す。

>>> c = [1]
>>> d = c
>>> # c += [2] だとc.append(2) と同じ挙動を示す
>>> c = c + [2]
>>> c is d
False

参考

stackoverflow.com

対処法

なんでこんなこと知っているのかというと、何度もハマったからである。これが原因のバグを何度見たことか。。。

たとえば、作為的な例だが

{1: [1, 2, 3, 10], 2: [1, 2, 3, 20], 3: [1, 2, 3, 30], 4: [1, 2, 3, 40], 5: [1, 2, 3, 50], 6: [1, 2, 3, 60], 7: [1, 2, 3, 70], 8: [1, 2, 3, 80], 9: [1, 2, 3, 90]}

という辞書を作りたいとする。最初の3つの要素は同じ、最後の1つだけ異なるという例だ。c = [1, 2, 3] として、 for 文の中で tmp 変数 d を作って、最後の i * 10 の部分だけ append しようなどと考えてコードを書いてしまうと。。。

>>> c = [1,2,3]
>>> dic = {}
>>> for i in range(1, 10):
...     d = c
...     d.append(i * 10)
...     dic[i] = d
...
>>> dic
{1: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 2: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 3: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 4: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 5: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 6: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 7: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 8: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90], 9: [1, 2, 3, 10, 20, 30, 40, 50, 60, 70, 80, 90]}

と、こんな感じでもともと欲しかったものとは全然違うものになってしまう。

これを避けるためには、ひとつの方法として deepcopy という関数を使うものがある。これはオブジェクトの実体をコピーする関数だ:

>>> from copy import deepcopy
>>> c = [1, 2, 3]
>>> dic = {}
>>> for i in range(1, 10):
...     d = deepcopy(c)
...     d.append(i * 10)
...     dic[i] = d
...
>>> dic
{1: [1, 2, 3, 10], 2: [1, 2, 3, 20], 3: [1, 2, 3, 30], 4: [1, 2, 3, 40], 5: [1, 2, 3, 50], 6: [1, 2, 3, 60], 7: [1, 2, 3, 70], 8: [1, 2, 3, 80], 9: [1, 2, 3, 90]}

しかしこの場合こんなもの使わなくても、内包表記であっさり書いてしまえる*1

>>> {i: [1,2,3, i * 10] for i in range(1, 10)}

結論

  • 不可解な挙動には一応理由があります(受け入れられるか受け入れられないかは別問題です)
  • 当然対処法もあります。リストや辞書の中身が想定と違うな?と思ったらこの類のバグを疑いましょう
  • 内包表記便利です、使いこなしましょう
  • なんか謎の記事を書いてしまったって気分。

*1:なので作為的な例なのだが。。。

今日も何もできなかった

何もできない

今日も何もできなかった。

最近毎日こんな調子だ。調子が悪い。何かを出し尽くしたか、何かを失ったか。

勉強したいことが山ほどあるわけでもなければ*1、好きな女の子に振り回されているわけでもなく*2、僕の時間は十分過ぎるほどに確保されているはずで、今日も1日自分の好きなように使える日だった。

一方で何をなしたかというと、何もなしていない。

変わりたい

思っていたよりも自分は今の生活に疲れていたのだということに気づく。

今は週末だけれど、平日は「明日もまた今日と同じか」と思うとひどく憂鬱になる。何も変わらない毎日が、つまらない。

そう簡単に人間は変わらない。知っている。

ご立派な経歴を持つ個々人が全く価値のないものに執着し、誰も望んでいないのに維持管理をする。そんな無為な日々を過ごしている人々をはたから見ている。他人にとって自分の仕事もきっとそう思われているのだと思うと、僕がやっていることは、やってきたことはなんだったんだろうかと自問する。

仕事は簡単には変わらない。

あまりにも自分が場違いな気がしてならない。僕は働けば働くほど、孤独になっていく。そんな感覚を覚える。

変われない

これを書いている今から24時間後、きっと僕は明日は憂鬱だと嘆き、変わらない毎日を嘆き、なにかにいちゃもんをつけながら明日をセブンイレブンでコーヒーを買っていつもの席に座り仕事を始める。

このまま自分が行動しなければ、また一歩自分が嫌っていた大人に近く。そんな危機感に煽られながら、何もできない自分にもどかしさを感じている。

こうして、徐々に2018年が近づいてくる。天国とは言わない、せめて自分にとって居心地のいい場所に行きたいと今は思う。

*1:当然余裕があればしたいのだが。

*2:それはそれで楽しいんだろうが。

散文 〜とりとめもなく思いつくままに〜

自分が成長している気がしなくなったのはいつからだろうか。

日に日に新しいことができるようになっているはずで、毎日成長しているはずだ。だけど、自分が変わっている気がしない。実際変わっていないのかもしれない。

以前は興味があったことに興味を失ったり、以前は楽しかったことが楽しく感じられなくなったり。

前回と同じことからスケールアップしたいのに、「時間がない」とか様々な理由をつけて同じことをなんども繰り返していたりして。

毎日、どんどんバカになっている気がする。

細かいことは言わないけれど、最近政治をすることが増えた。政治というほどの段階までは来ていないといえば来ていない。どちらかというと「根回し」や「調整」という言葉が近い。

僕はこの「根回し」や「調整」が下手な人間であることを自覚している。僕が直接に口や手を出すとうまくいかないので、基本的に僕が手の届く範囲の人で仲間を作り*1、その仲間に根回しや調整を実行してもらうことが多い。ここでなけなしのコミュニケーション能力を振りしぼるのである。

この行為は正直言ってものすごく疲れる。今までは自分の独断で色々とやってきたが、色々と事情があって自分だけでなんでもやるというのはさすがに無理になってきた*2。なのでこうした疲れる工程を踏む必要が生じて来た。

どちらがいいでもない、トレードオフだ。自分が全責任を取れるなら独断でもいいが、何せ僕は取締役でもなんでもない。責任がとれないなら情報の共有をきっちりし、然るべき人の許可をとって実施するべきだ。今までのことは棚にあげる。

多かれ少なかれ、自分のやりたいことを実現するためにはそうした前段階の工程が必要で、自分たちが何を求めているのか、どんな環境にするべきか、どんな環境であるべきなのか。そうしたことを責任者に向かって発信し、認めさせるというプロセスを踏むべきだ。

と、息巻いていたわけだが、最近は諦めが先に立つようになった。

諦めの理由は然るべき時が来たら書くかもしれないが、ぼかして書くと、僕の人格でもコミュ力でも技術力でもない理由で僕の意志がないがしろにされる状態に陥ったからだ。

今までも不満はあったが、自分の至らなさが根底にはあった。しかし最近は自分にはどうすることもできない理由で意思決定の場に参加できなくなった。

おかげで、いろんなことがどうでもよくなった。

明日自分が何か新しいことをできるようになっている期待もなく、明日は今日よりも仕事がやりやすくなっているという期待もなく、ただ漫然と平日が過ぎるのを待ち、休日を待つ。

そんな会社員に、僕もなっていくのだろうか。

いつからだろう、かつて嫌っていた人間にどんどん自分が近づいて行くと気づいたのは。

金とセックスの話しかできない会社員なんていやだ、と書いたのはいつだったか。僕はまた、嫌いな大人になるのだろうか。今の僕は、一年前の僕が嫌っていた大人じゃないだろうか。

そんなことを思いながら眠りにつく。

*1:ここで失敗するとかなり大変なことになる。下手な人間を仲間にするとあとで自分が疲弊する。

*2:どちらかというと今までが異常だった。

帰るべき場所

帰る

「帰る」と言う。「帰省」とか、「帰宅」とか様々な帰るべき場所、帰るという行為がある。

僕はいま一人暮らしをしていて、アパートの一室を借りて暮らしている。そこに戻ることが「帰宅」である。

大学時代は実家で暮らしていて、「帰宅」は実家に帰ることだった。今は実家に帰ることは「帰省」だ。帰る場所が同じでも状況や頻度、自分が住んでいる場所などよって、言葉は変わる。人には自分が住んでいる場所と、住んでいなくても定期的に帰るべき場所がある。

さも、帰るべき場所があって当然かのように。

東京

東京へ行って来た。理由は仕事だ。仕事のことはここには書かない。

東京という街に「帰った」ことはない。 僕にとって今までずっと東京は「行く」場所だった。友達は居るけど、家族も親戚も関東地方にいない。だから東京へ「帰る」ことは今までありえなかった。

僕の帰るべき場所は、実家や、京都だ。それは今のうちはそうだと思っていた。

変わらない場所

一方で、僕は変わらない場所を嫌っている。僕は変わり続けたい、僕はこれまでも成長し続けたい*1、視野を広げたい。

blog.515hikaru.net

高校を隣の市にしたのも、遠い大学を受けようとしたのも*2、就職するときに地元にこだわらなかったのも全部同じ理由だ。

僕が変わるために、僕が僕を変えるために、僕は外へ行く。それが僕が今まで「進路」を選んで来たひとつの基準だった。

変わり続ける場所

昨日まで東京にいた。仕事もし、後輩と食事をとったりコーヒーを飲んだりした。

僕が住んでいるわけではないが、そこに住んでいる人たち、そこで生きている人たちと直接話した。

ふと、気づいた。この街は変わり続ける。勝手に。

お金がある、人がたくさん居る。再開発の恩恵に預かる人、生存競争の中で淘汰されてしまう人、進学する人、様々な理由で東京へ来る人、東京を出る人がいる。

勝手に人が出入りする、勝手に街が変わる。自分を変えようとしなくても。

住んだことはないから僕の買いかぶりかもしれない。

住みたい場所、住むべき場所、帰りたい場所

それを思って京都に帰って来た。そう帰って来たはずだ。でも全く落ち着かない。

少し前まで「日常」だったはずのコンビニ、少し前まで「当たり前」だったはずのスーパー、少し前まで行きつけだったバー。

どこにいても、帰って来た気がしない。

この三日間で東京に惹かれてしまったのかもしれない。

ここにいても変わらない、そんな閉塞感にまた打ちひしがれ始めている。勝手にひとつ、帰りたい場所を失った。

また、場所をうつすかもしれない。「住みたい場所」を帰りたい場所にするため。帰るべき場所にするため。

僕を変え続けるため。

*1:これは職業的にも数学や映画といった趣味に関しても。

*2:様々な事情で結局実家から通える大学に通うことにした。今は後悔していないが、もしやり直せるならもう一度同じ大学は受けないだろう。

権利について

いつもいつも、政治の報道は何か他のニュースにかき消されている気がする。

が、これを書いている今日*1は衆議院を解散すると安倍総理が記者会見した日である。

logmi.jp

安倍首相は25日に記者会見を開き、アベノミクスの2大改革である生産性革命、人づくり革命について演説。また、それにあたり、28日召集の臨時国会で衆院を解散する意向を表明しました。

解散をするということは当然、選挙をするということである。僕は選挙のたびに、そして2017年になってより強く思うようになったことがあるのでここに書き記しておこうと思う。

*1:2017年9月25日。書いているうちに日付が変わったので投稿日時は26日になっている。

続きを読む

独自ドメインにした

特に目的とかがあったわけではないんだけど、自分用の Wiki をなんとなく立てたくなって HTTPS の対応とかしていたらいつの間にか独自ドメインを手に入れていたので、ついでにこのブログも独自ドメイン化しました。

blog.515hikaru.net です。覚えやすいですね。*1

他のブログは GitHub Pages にホストしているので、そちらも SSL 対応しつつ独自ドメイン対応をしていく予定です。

言い訳


最近更新頻度が落ちていますが、理由としては、基本ここには書けないことで頭を悩ませているからでしょうか。

忙しくはない*2んですが、結構悩むことが増えました。そしてその悩みをあまり表に出さないように努めていたりします。

言える段階まで来たら色々と言おうかと思いますし、暇になったら更新頻度も今よりはあがってくるんじゃないかと思っています。

そんなことよりはやくダンケルクを見てほしい。

wwws.warnerbros.co.jp

*1:本当か?

*2:ただこれから忙しくなりそうな気配はある。

だからなんだって思うだろうけど

仕事で地方に行くことがある。

その際にほぼ必ずと言って感じるのは、「喋るのが遅い」ということだ。

僕は別に喋るのが早い方ではない*1のだけど、その僕が他の人のことを遅いと思うのだから、やはり遅いのだと思う。いま京都暮らしだが、誰かと話していて喋るのが遅いと感じたことは一度もない。

だからなんだって思うだろうけど、本当にそれだけだ。

例えば都会の人は早口なんだとか色々てきとうな理屈をこねて書き足すこともできるんだろうけど、別に何かを主張したいわけじゃない。

ただ、気づいたことをどこかに書きたかったし、Twitterみたいな場所じゃなくて、ひとつページを割いてこのことに気づいたって書きたかった。

ただそれだけ。

*1:と自分では思っている。