プログラミングを趣味にしたい

UE4、scala、ゲーム作り、webアプリ制作とか手を出しているPC系趣味について書き溜めるブログ。現在大規模改装中

このブログは現在リブート中です。 予告なく変更、削除、停止を行う場合があります。
回収作業が終わったらこの文章は削除します

pythonのpathlibでリネームしたときに、すっごい馬鹿なミスしてエラーで彷徨ったので備忘録

pythonのpathlibでのリネーム作業において、小一時間無駄に彷徨ったのでメモ書き程度の備忘録

とある複数のフォルダ(ディレクトリ)があるとして、その中に大量のファイルが入っている。それを一括リネームした上で親フォルダに移動させたかった。
が、リネームしたあとに移動させようとしたらエラーが出た。
めちゃくちゃしょうもないミスだったが、まぁ自戒を込めて備忘録にしておく。

これは誰に見られることも想定していない落書きであるので注意。


経緯

トドの、つまり

親フォルダ : test の中に
test / dir1
test / dir2
test / dir3
....

という具合にフォルダが入ってて、

各dirの中に
test / dir1 / a
test / dir1 / b
test / dir1 / c
...

という具合に大量のファイルが入ってる。
これのファイルをファイル名の頭にフォルダ名を入れた上でリネームし、testフォルダ直下に

test / dir1_a
test / dir1_b
...
test / dir2_a
test / dir2_b
...

みたいにまとめたかった。
で、後で直下に置くファイルを正規表現でフィルターかけるとかの複雑処理を足すかもしれんかったので、ちゃちゃっとpythonで書こうとしたわけだ。

そしたらエラーが出た。
「no such file」

なんで??????

printデバッグするとわかった当たり前の原因

どうせ適当に使ったshutil(高水準ファイル操作ライブラリ)のせいだろうと決めつけ、あーでもないこーでもないとドツボにはまりだした。
言い訳させてくれ。
以前shutil.moveのエラーに引っかかってたのが尾を引いていた。
(shutil.moveちゃんはなぜかファイルを親ディレクトリに移動しようとするとエラーを吐く。多分私の使い方が間違っているだけだと思う。
なんで仕方ないのでcopyした後ディレクトリごと削除(rmtree)する。)

今回はちゃんとshutil.copy+shutil.rmtreeにしたのになぁ・・・。

書いたコードの一部がこれ

・・・
#リネーム後の名前は「フォルダ名_ファイル名」
target = Path(p).name+"_"+Path(a).name
#targetにリネーム
Path(a).rename(Path(a).with_name(target))
#親ディレクトリにコピー
shutil.copy(Path(a) , Path(p).parent)
・・・

・・・ええ、まっとうなpython使いの方なら

「こいつなにしてんだ。馬鹿じゃね?」

ってなったと思う。
しかし、当時の私は思考の袋小路。
shutil.copyの使い方が悪いのかとshutilのドキュメントを読みに行く始末。

バカジャネーノ(;・∀・)

実装5分ぐらいで終わらす予定が、エラー画面をはいてからもう40分くらい過ぎた。。。。
実装時間合わせると10倍近い時間がかかってることになる。
これはいけない。
もうにっちもさっちもいかなくなったので、とにかくステップごとの情報を見ることに。
とはいえ、そもそもpythonでの作業自動化は、大抵はエディタでサクッと書くのでIDEを使っていないし使う気もない。
仕方ないので、各所にprint()を差し込んで古式豊かなprintfデバッグでのローラー作戦を試みる。
C言語時代を思い出すなぁ。


そしたらどうよ!


原因

test/dir1/a において

・・・

#リネーム後の名前は「フォルダ名_ファイル名」
target = Path(p).name+"_"+Path(a).name

=>ここまで、Path(a)はtest/dir1/aを指している。

#target名にリネーム
Path(a).rename(Path(a).with_name(target))

=>この時点で、元ファイルは test/dir1/dir1_aに変更
しかし当然ながら、変数aは更新されておらず・・・・・・・・「Path(a)はtest/dir1/aを指している」まま。

#親ディレクトリにコピー
shutil.copy(Path(a) , Path(p).parent)

=>Path(a)を見に行くものの、すでにリネーム済みなのでtest/dir1/aは存在せず、dir1_aしか無い。
=>エラー「そんなファイル無いです」

あーなるほど。
Path(a).renameはリネーム後の変数が指すパス位置を変更してくれないらしい。
まぁでもそうだよね。変更したら副作用出るもんね。



バカジャネーノ?????
なんでこんなんに40分もかけてんだ???
アニメ2話ぐらい見れるんだが?????
わたてん二周できたんだが?????
(今期アニメ、「私に天使が舞い降りた!」はいいぞ!原作も、読もう!)

サクッと付け足す

#リネーム後の名前は「フォルダ名_ファイル名」
target = Path(p).name+"_"+Path(a).name
#withname は現在パスのファイル名を変更したもの
Path(a).rename(Path(a).with_name(target))
b = Path(a).with_name(target)<=追加
#ファイルを親ディレクトリに移動
shutil.copy(Path(b) , Path(p).parent)

普通に動きました(´;ω;`)

ああああああああああああああああああああああああああああああああ

返してよー私の時間・・・・・

教訓

ファイル操作のときは副作用が出るんだから、ちゃんとフローの流れは頭においておこうな!
副作用が怖いならちゃんと関数型プログラミング系の書き方しような!

いや、

そういう問題じゃない気がする。

そもそも、エラー原因を特定してないのに「no such file」のエラーメッセージだけでshutilちゃんのせいにしたのが悪かった。
ごめんよshutilちゃん。

教訓:簡単なプログラムでも横着しないで、エラーの原因を切り分けてから問題解決に移りましょう。

関連記事

ないです