kick the base

Houdiniと、CG技術と、日々のこと。

Python: ランダムなファイル名を持つテキストファイルを複数作成する04 -モジュールの利用と今までの総括

本連載も今回で最後です。今までの知識に加えrandomモジュールstringモジュールを用いてランダム文字列の生成を行えるようになりましょう。

また、最後にVimから外部プログラムを呼び出して自身のPythonコードを実行する手順も簡単にご紹介します。

環境

  • OS X 10.11.6
  • Python 3.4.4

最終的なコード

いままで上記を最終的なコードとしてきましたが、まず最初に長すぎる行のコード規約エラーについて回答を示しておきます。

区切りの良いところで改行を入れる

Pythonはカッコで囲まれた部分は改行を含んでいても連続したものとして認識してくれるという特徴があり、それを利用します。

import random
import string

digit = 8
random_str = ''.join(
    [random.choice(string.ascii_letters + string.digits)
     for _ in range(digit)])
print(random_str)

これで長過ぎる行は解消されました。しかし上記だと単に長い文を問題が発生しない位置で折り返しただけなので、スマートな解決策とは言いがたいですね。もっと構造的に見やすくしたほうが良いでしょう。

適切な変数を用意する

8行目、sourceという変数を用意することによって見やすくしたということです。コード規約に怒られたから改行して回避するのではなく、アラートの意図を組んで対応したほうがより良いコードになるかと思います。

こちらの方が見やすいので、本コードで解説を進めていくことにしましょう。

モジュールのインポート

import random
import string

一番最初にtools.pymain.pyの解説でしれっと使ってしまいましたが、モジュールのインポートはこのように行います。

モジュールというのはある機能に特化した道具箱みたいなものだと思ってください。

randomモジュールはその名の通りランダムに関する処理を、stringモジュールはその名の通り文字列に関する便利な道具がいっぱい入っています。*1

また、モジュールというと仰々しい感じがしますが、中身は単純なPythonファイル(モジュール名.py)です。

そんな便利なものだったら最初から入れておけばいいじゃないかと思われるかもしれませんが、最初からてんこ盛りの状態では非常に重くなってしまうので、起動時は身軽な状態でスタートし、必要に応じてインポートするという仕組みになっています。

モジュールを使ってみる

例としていくつかモジュールを使ってみましょう。すでにインポート済みの状態とします。

randomモジュール

random.randintメソッド

random.randintメソッドはランダムで整数を取り出すメソッドです。

random.randint(1, 5)

この例では実行するたび1, 2, 3, 4, 5を取り出します。

random.choiceメソッド

random.chiceメソッドは引数にシーケンス型*2をとり、そこからランダムで取り出します。

random.choice('abc')

上記例では実行するたびa,b,cをランダムで取り出します。

stringモジュール

string.ascii_letters定数

すべてのアルファベットであるabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZを取り出すことができます。

string.digits定数

数字0123456789を取り出すことができます。しかし、注意すべきはこれはstringモジュールの定数だということです。つまり取り出した数値は文字列型です。

すべてを組み合わせる

今までの知識を総動員してコードを読んでみましょう。

source = string.ascii_letters + string.digits
random_str = ''.join([random.choice(source) for _ in range(digit)])

上記コードを分解していきましょう。

ランダム文字列のベースとなる文字列+数値を用意する

source = string.ascii_letters + string.digits

前述の説明の通り、sourceの中身はabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789となります。

リスト内包

[random.choice(source) for _ in range(digit)]

次にここ、内包表記ですね。rangeオブジェクトの引数にdigitが渡っていますが、これは桁を意味している変数で自分で決めたものです。ファイル名を8桁のランダムにしたければ8を、4なら4桁になります。そして添字は使用しないので_としています。つまりfor _ in range(digit)の部分は単純にdigitの数だけループするという意味になります。

つぎにrandom.choice(source)の部分です。これはsourceからひとつ抜き出すという意味です。

そしてこれをリスト内包としたことで、アルファベットと数字から1文字抜き出したものをdigit個だけ要素に持つリストができあがったわけです。

最後に説明していなかったjoinメソッドですが、これは文字列を要素に持つイテレート可能オブジェクトの各要素をつなぎ合わせた文字列を返すメソッドです。

これも例を用意しましょう。

joinメソッド

print(''.join(['a', 'b', 'c']))  # abc
print('-'.join('arigato'))  # a-r-i-g-a-t-o
print('☆'.join(('つのだ', 'ひろ')))  # つのだ☆ひろ

''(シングル・ダブルクオーテーション)の中に文字列を入れると、その文字列でイテレート可能オブジェクトの要素一つ一つをつないで返してくれます。

これでめでたくアルファベットと数字からなるランダムな文字を指定回数だけつなげた文字列を得ることができました。

Vimから外部プログラム呼び出し自分自身をPythonで実行する

Pythonコードが本連載のメインなので、ここは簡単に動画の手順だけ解説します。

  1. treeコマンドで現在のディレクトリの内容を確認
  2. $ vim create_rand_filenames.pyコマンドを実行
  3. :!python %で現在のファイルを外部プログラムで実行
  4. vimに戻ったらC-zでvimを中断
  5. command + Kで画面をクリア(後のtreeコマンドが長いため)
  6. treeコマンドで現在のディレクトリの内容を確認。ファイルが生成されているのが分かる

f:id:kickbase:20161005233841g:plain

まとめ

いかがでしょうか。駆け足で説明したため割愛した箇所も多かったですが、大体の雰囲気はつかめたかと思います。このツールは他のスクリプト言語でも実装できますが、Pythonもぜひ候補に入れてみてください。

備考

今回はもともと複数ファイルのリネームがメインの記事だったので、ある程度の個数ファイルが生成されていればよかったため、このような実装になっています。forループは10回ですが、低い確率で同じファイル名が出ることもあるでしょう。

'w'オプションでopenを実行した場合、同じファイル名では上書きになるのがPythonの仕様でした。つまり確実にループ回数だけファイルを作成するという処理を実現するためには、本コードを改造する必要があります。

色々なやり方があると思うので、ご興味がある方はトライしてみてはいかがでしょうか。

*1:この「その名の通り」というのが大切で、自作モジュールを作る際も用途が分かりやすい名前をつけましょう

*2:文字列、リスト、タプルなど