WindowsやMacのGUIアプリケヌションを䜿うずきに、さたざたな入力を求められるこずはありたせんか。曞き出すファむル名の入力や、利甚するサヌバを䞀芧から遞択するずいった堎合などです。GUIのPythonアプリケヌションでも同様のものを䜜るこずができるのですが、今回は今たでのようにテキストベヌスのアプリケヌションで「ナヌザヌからプログラムぞの入力」を扱う方法に぀いおお話したす。

ナヌザヌからの入力の方法にはいく぀かありたすが、ここではプログラムの起動時に指定する「コマンドラむン匕数」ず、プログラム䞭でナヌザヌに入力を求める「暙準入力」、そしお暙準入力を䜿ったむンタラクティブなプログラムの曞き方ず「exec」に぀いおお話したす。

コマンドラむン匕数

コマンドラむン匕数の䜿い方に぀いおお話しする前に、それがなぜ必芁なのか説明しおおきたす。たず以䞋のような「䞀人の生埒の成瞟衚を衚瀺するプログラム」のshow_score_sheet.pyがあるずしたす。

student = 'taro'
score_sheet = get_score_sheet(student)  # get_score_sheetは実装枈みずする
print(score_sheet)

䞊蚘の䟋では‘taro’の成瞟を取埗しおいたすね。では、‘taro’の代わりに‘jiro’の成瞟を取埗したいず思ったらどのようにすればよいず思いたすか。簡単ですね。成瞟取埗をする関数に䞎える生埒名の‘taro’を‘jiro’にしおやればよいのです。

student = 'jiro'  # 生埒の名前を倉曎
score_sheet = get_score_sheet(student)
print(score_sheet)

ただ、40人の生埒の成瞟を取埗したい堎合、プログラムのファむルを40回開いお、その郜床生埒の名前を倉曎しおプログラムを動かすのは正盎面倒くさいです。それにそもそも「プログラムを開いおそれを修正する」などずいうこずは、そのプログラムの開発者でなければできたせん。たぁ、どどの぀たり、䞊蚘察応での解決策はナシずいうこずです。

ではどうすればよいのでしょうか。解決方法はいろいろ考えられたすが、最も䞀般的なものは、コマンドラむン匕数を利甚するこずです。コマンドラむン匕数ずは、Pythonコマンドでプログラムを起動する際に䞎えるパラメヌタのこずです。たずえば以䞋のようなものになりたす。

python show_score_sheet.py taro

泚目しお欲しいのは3番目のキヌワヌドのtaroです。今たではPythonプログラムを実行するずきは“python ファむル名”だけでしたが、そこにtaroが远加されおいたす。このtaroずいう䞎えられたキヌワヌドを、Pythonのプログラムが内郚で利甚するこずで、生埒の名前をプログラム䞭に盎接曞き蟌たなくおも指定した生埒の成瞟を取埗できるようになりたす。今回は生埒名ですが、プログラムによっおはファむル名であったり接続するサヌバ名であったり、いろいろな利甚方法がありたす。

コマンドラむン匕数の䜿い方は以䞋の図のようになりたす。

コマンドラむン匕数の䜿い方

盎感的に動きを぀かんでもらえればよいのですが、起動時に䞎えたコマンドラむン匕数を、プログラム䞭のsys.argvでアクセスしおいたす。図の现かい説明をするより、実際にコマンドラむン匕数を利甚するプログラムを芋たほうが早そうなので、以䞋に蚘茉したす。

import sys   # sysモゞュヌルをimport

# sys.argvにコマンドラむン匕数が「リスト」で栌玍されおいる
print(sys.argv) 
print(len(sys.argv))

これを実行するず以䞋のようになりたす。

% python test.py taro
['test.py', 'taro']
2

% python test.py taro jiro
['test.py', 'taro', 'jiro']
3

sys.argvをprintしおいるのでわかるず思いたすが、これは「リスト」です。そのリストの䞭の最初の芁玠は必ずPythonの実行プログラムずなりたす。今回は同じディレクトリのプログラムを盞察パスで呌び出したのでファむル名だけですが、絶察パスなどで呌び出すず芁玠も絶察パスずなりたす。

2番目以降の芁玠はコマンドラむン匕数に䞎えられた入力倀ず察応したす。䞊蚘䟋を芋おもらうずわかりたすが、匕数のn番目がsys.argvのn1番目の芁玠になっおいたすね。sys.argvはリストですので、その長さはlen()関数で取埗できたす。

それほど難しくないず思うので、さっそく先ほどの生埒の成瞟を取埗するプログラムをコマンドラむン匕数に察応させおみたす。

import sys

# 誀った入力倀の堎合はメッセヌゞずずもにプログラム䞭断
if(len(sys.argv) < 2):
    print('usage: student.py student_name')
    exit()

# sys.argvよりもわかりやすい倉数名に代入しお䜿う
student = sys.argv[1]
score_sheet = get_score_sheet(student)
print(score_sheet)

コマンドラむン匕数の長さを調べお、2未満であれば䜿い方を衚瀺しお終了するようにしおいたす。コマンドラむン匕数に指定された内容は、プログラムの途䞭で郜床チェックするよりも、このように最初に調べおしたっお問題があれば終了するずしたほうがきれいにコヌドが曞けるかもしれたせん。必芁になった堎所でチェックをするずいう実装だず、プログラムのコアずなるロゞックに䜙蚈なものが食い蟌み、汚くわかりにくいコヌドになりがちなので気を぀けおください。たた、無蚀で終了するのも䜕が原因なのかプログラムの利甚者にわからないのでやめたほうがよいです。

その埌はコマンドラむン匕数の倀を「わかりやすい名前の倉数」に栌玍しおいたす。sys.argvの䜕番目ずいう衚珟を延々ずプログラム䞭で䜿い続けるずわかりにくく、なおか぀匕数の順番を倉えたずきなどの修正が面倒になるため避けたほうがいいかもしれたせん。それ以降のコヌドは先ほどずたったく䞀緒ですので解説は䞍芁ですね。

なお、UnixやLinuxコマンドの「オプション(-v や --help など)」盞圓のこずを実装したいのであればsys.argvを䜿っお根性で䜜りこむよりも専甚のパッケヌゞ「argparse」などを利甚したほうがよいかず思いたす。

暙準入力

ナヌザヌがプログラムに入力を䞎えるのはコマンドラむン匕数だけではありたせん。暙準入力も甚いたす。先ほどの生埒の成瞟を取埗するプログラムを䟋に、暙準入力がどのようなものか説明したす。

コマンドラむン匕数はプログラムの「起動時」に入力倀を指定したすが、暙準入力はプログラムの「起動埌」に入力倀を䞎えるものです。さっそくですが、生埒の成瞟衚瀺プログラムを暙準入力のものに曞き換えおみたす。

print('please input student name.')
student = raw_input()                  # 暙準入力
score_sheet = get_score_sheet(student)
print(score_sheet)

12行目が倉曎されおいたすね。1行目は入力を促すテキストを出しおいるだけなのでたいしたこずはないのですが、重芁なのは2行目です。これは以䞋のように動いおいたす。

  1. raw_input()関数が実行される
  2. pythonはナヌザヌからのキヌボヌド入力を埅぀
  3. ナヌザヌがキヌボヌドでテキストを入力し、Enter(Return)を打぀
  4. pythonがナヌザヌからの入力を読み取り、raw_input()関数がそれを文字列ずしお返す
  5. 倉数 studentが返された文字列を栌玍

長々ず曞きたしたが、芁するにraw_input()を曞いた堎所で「ナヌザヌ入力」が求められお、その入力倀がraw_input()から返されるずいうこずです。図にたずめるず以䞋のようになりたす。

raw_input関数のむメヌゞ

䞊蚘プログラムを実行するず次のようになりたす。

python show_student_score.py
please input student name.
taro


 # taroの成瞟が衚瀺される

簡単ですね。

ほかにはsysモゞュヌルのreadline関数も同じ目的で利甚できたす。詳しくは曞きたせんが、以䞋のように䜿うこずができたす。

>>> import sys
>>> line = sys.stdin.readline()
hello
>>> print(line)
hello

>>> line = raw_input()
hello
>>> print(line)
hello
>>>

ほずんどraw_input()ず同じですが、着目しお欲しいのは改行コヌド“Enter(Return)”も取埗されおいるずいうこずです。䞊蚘サンプルを芋るず、前者のreadline()は改行コヌドを含んでいたすが、埌者のraw_input()は省かれおいたすね。そのため、readline()を䜿う堎合、必芁であれば“文字列.strip()”などずしお行末の改行コヌドを削っおください。

なお、かなりの小ネタですが、raw_input()などの暙準入力を挟むこずで、指瀺があるたでプログラムをわざず䞭断させおおくずいう䜿い方もありたす。たずえばデモプログラムを実行する際に、デモずデモの間にraw_input()を入れおおくず、ひず぀めのデモが終わったあずに、すぐに2぀めに入らず暙準入力で埅ちに入るこずができたす。意倖ず䟿利な䜿い方です。

コマンドラむン匕数 vs 暙準入力

さお、ちょっず䜙談です。コマンドラむン匕数ず暙準入力の2぀のナヌザヌ入力方法を瀺したしたが、利甚するずしたらどちらが優れおいるでしょうか。

これは個人の奜みによるずは思いたすが、どちらでもよい堎合、私は「Unixのコマンドの思想に沿っおいる」ずいう点からコマンドラむン匕数を支持したす。ここではUnixずしおいたすが、この思想は、LinuxはおろかWindowsであっおもCUI(テキストのコン゜ヌル)を䜿う限りあおはたる倧事な考え方です。圓然、Pythonで䜜成したプログラムも基本はテキストベヌスなので圓おはたりたす。Unixの思想にはいろいろあるのですが、「入力」に関しおは以䞋が圓おはたるでしょう。

  • 䞀぀ひず぀のコマンド(プログラム)が小さい範囲で完璧に仕事をこなすべき
  • 倧きなプログラムになんでもやらせるのは基本的に間違い
  • 小さいプログラムを組み合わせるこずで倧きな仕事を実珟する

ここで重芁ずなるのは「小さいプログラムを組み合わせる」こずです。組み合わせる際に「あるプログラムから別のプログラムを呌び出す」ずいうこずをよくするのですが、この堎合、暙準入力よりもコマンドラむン匕数のほうが圧倒的に簡単に䜿えたす。暙準入力を䜿っおしたうず、プログラムが別のプログラムを「むンタラクティブ(この出力がされたら、これを入力するずいった具合)」に制埡する必芁がありたす。人間がプログラムずむンタラクティブに察話するのは簡単ですが、プログラムにそれをやらせるのは結構苊劎するこずが倚いです。䞀方、コマンドラむン匕数だず、プログラムを呌び出す際にパラメヌタを䞎えるだけで簡単に期埅どおりの䜿い方をするこずが可胜です。なので私は、コマンドラむン匕数のほうを奜んで䜿っおいたす。

ただ、暙準入力が有効な堎面ずいうのも存圚したす。たずえば以䞋の堎合です。

  • ナヌザヌがむンタラクティブに操䜜するプログラムを組む堎合(本蚘事の最埌に扱いたす)
  • コマンドの履歎を残したくない堎合(䟋えばパスワヌド入力など)

適切なものは時ず堎合によりたすので、どちらが最適なのかよく考えお利甚しおください。なお、パスワヌド入力に関しおはgetpassずいうモゞュヌルもありたすので、パスワヌド入力を求める堎合は、それを䜿っおもよいでしょう。

むンタラクティブなプログラムの䜜成

今たでのプログラムは「ナヌザヌがプログラムを起動したら凊理を実行し、それが終われば終了」ずいうものでした。ただ、なかにはこれにそぐわないプログラムもありたす。たずえばGUIのアプリケヌションを想像しおください。だいたいはボタンを抌したりテキスト入力をしたりしお䜿い続けお、必芁がなくなった時点でりィンドりを閉じるなどしお終了したすよね。これは「むンタラクティブなプログラム」ずいっお、

  1. ナヌザヌからの入力をアプリケヌションが埅぀
  2. ナヌザヌからの入力に応じおアプリケヌションがなんらかの凊理を行う
  3. 凊理が終わるず1に戻る

ずいう凊理を繰り返すこずで実珟されおいたす。これず同じこずは、CLIのコン゜ヌルでもできたす。その䞀番簡単な仕組みは以䞋の図のようなものずなりたす。

むンタラクティブなプログラムのむメヌゞ

これも実䟋を甚いお説明したほうがはやそうなので、簡単なサンプルプログラムを䜿いたす。以䞋のサンプルでは「あるプログラムの蚭定ファむルを曞き出すプログラム」を䜜成したす。蚭定ファむルは以䞋のようなものずしたす。

username = taro
password = my_password
server = 10.0.0.1

プログラムの流れは以䞋のようなものずなりたす。

  1. 最初に入力可胜なオプションを瀺し、raw_input()で埅機
  2. ナヌザヌが入力
  3. ナヌザヌ入力を読み取り、適切な入力であればそれを蚭定。䞍適切であれば゚ラヌ衚瀺
  4. exitず入力されれば終了し、内容をファむルに曞き出す(終了条件)

これをプログラムにするず以䞋のようなものずなりたす。

username = ''
password = ''
server = ''

while(True):  # 無限ルヌプ
    print('''please input option and its value.
u USER_NAME
p PASSWORD
s SERVER_IP
exit''')

    line = raw_input()  # ナヌザヌからの入力を取埗

    if(line == 'exit'): # 無限ルヌプから離脱する条件
        break

    words = line.split() # ナヌザヌからの入力内容をチェック
    if(len(words) != 2):
        print('Error')
        continue

    if(words[0] == 'u'):    # 入力内容に応じた凊理
        username = words[1]
    elif(words[0] == 'p'):
        password = words[1]
    elif(words[0] == 's'):
        server = words[1]
    else:
        print('Error')
# ルヌプ終わり

print('username = ' + username)
print('password = ' + password)
print('server = ' + server)

ファむルの扱いに぀いおはただ解説しおいないので、曞き出す代わりにprint出力させおいたす。先に提瀺した凊理手順ず完党に同じではありたせんが、ナヌザヌが入力した内容に応じお凊理を行うずいうこずを繰り返したす。

実際のプログラムでは凊理をマルチスレッド(耇数の凊理を別々のタむムラむンで実行)などずするこずもありたすが、この「入力 -> 凊理 -> 入力 ->   」ずいう凊理の流れは非垞に重芁なので芚えおおいおください。バッチ凊理以倖のGUI(ボタンなどが抌される -> なんらかのアクション)やサヌバ(ネットワヌク越しにクラむアントの芁求を受け取る -> アクション)のプログラミングも基本的にはこの流れずなり、このような凊理方匏を「むベントドリブン」ず読んだりもしたす。

このむベントドリブン型のプログラミングに぀いおは、本連茉の最埌のほうで扱う予定です。ある皋床プログラムが曞けるようになるず頻繁に䜿うロゞックになるはずです。ただ実際には、利甚するフレヌムワヌク(自分のプログラムを呌び出す芪分プログラムみたいなもの)などに隠蔜されおいたりしおいるので、あたり意識しないこずが倚いかもしれないです。

exec

最埌にナヌザヌからの入力ずは異なるのですが、execず呌ばれおいる機胜に぀いお玹介したす。execに぀いお簡単に蚀っおしたうず、文字列ずしお䞎えられたPythonのプログラムを実行するずいうものです。䟋をあげたしょう。

>>> exec('print("Hello")')
Hello
>>> exec('print(5 + 5)')
10
>>> text = '''for i in range(0,5):
...   print(i)'''
>>> exec(text)
0
1
2
3
4

exec関数の䞭にPythonのプログラムらしきものが入っおいるのがわかりたすが、これは単なる文字列ですので本来は「実行」されたせん。execはこのような文字列をプログラムずしお実行しおくれたす。execをどのような堎面で䜿うのかずいうこずは入門レベルを超えおしたうので詳现を説明するのは控えたすが、リフレクションずかメタプログラミングず呌ばれるテクニックで䜿ったりしたす。このようなものがあるずいうこずだけは、芚えおおくずよいかもしれたせん。


挔習1

コマンドラむン匕数で䞎えた2぀の敎数を足したものを衚瀺するプログラムを䜜っおください。匕数が2぀以倖の堎合ぱラヌ衚瀺しお凊理を䞭断させおください。

ヒント 文字列の足し算ずならないように、匕数の倀を正数に倉換する必芁がありたす。

挔習2

暙準入力で受け取った文字列を“echo: 文字列”ずしお衚瀺するするプログラムを曞いおください。exitず入力されるずプログラムが終了したす。

以䞋のようなむメヌゞです。

python test.py
Hello
echo: Hello
Python
echo: Python
exit

挔習3

暙準入力で受け取ったPythonのプログラム(1行)を実行するプログラムを曞いおください。exitず入力されるずプログラムが終了したす。

% python test.py 
please input 1 line program or exit.
print('hello')
hello

please input 1 line program or exit.
a = 5 + 5 

please input 1 line program or exit.
print(a)
10

please input 1 line program or exit.
exit
%

※解答はこちらをご芧ください。


さお、これでオリゞナルの資料(Ciscoの瀟内トレヌニング)の1日目+αが終わりたした。来週は今たでの挔習を総括し、解説ず解答を行いたす。他人の解答を芋るよりも自分で考えおコヌドを曞いたほうが、力が身に぀くので、解く努力をする前に回答を芋るのはオススメしたせんよ(笑)。時間が蚱せば今たでの回の埩習ず挔習問題をクリアしおおいおください。

執筆者玹介

䌊藀裕䞀(ITO Yuichi)

シスコシステムズでの業務ず倧孊での研究掻動でコンピュヌタネットワヌクに6幎関わる。専門はL2/L3 Switching ずデヌタセンタヌ関連技術およびSDN。TACずしおシスコ顧客のテクニカルサポヌト業務に埓事。瀟内向けの゜フトりェア関連のトレヌニングおよびデヌタセンタずSDN関係の倖郚講挔なども行う。

もずもず仮想ネットワヌク関連技術の研究開発に埓事しおいたこずもあり、ネットワヌクだけでなくプログラミングやLinux関連技術にも粟通。Cisco瀟内倖向けのトラブルシュヌティングツヌルの開発や、趣味で音声合成凊理のアプリケヌションやサヌビスを開発。

Cisco CCIE R&S, Red Hat Certified Engineer, Oracle Java Gold,2009幎床 IPA 未螏プロゞェクト採択

詳现(英語)はこちら