Python/プログラマのように考えるには/プログラミングのやり方
この本の目的は、読者を計算機科学者と同じような考え方ができるようにすることです。 この考え方はとは、数学者、エンジニア、科学者のよいところをあわせた考え方です。 計算機科学者は、数学者のように、自分の考えていること(特に計算に関すること)を表現するのに形式言語を使います。 計算機科学者は、エンジニアのように、設計し、部品を組み合わせてシステムをつくり、選択肢のトレードオフを評価します。 計算機科学者は、科学者のように、複雑なシステムの振る舞いを観察し、仮説を立て、予測をテストします。
計算機科学者にとって、唯一重要な能力は、問題を解決する能力です。 問題解決とは、問題を定式化し、解決方法を考え、解決方法を明快で正確に表現できる能力のことです。 この本読み終わる頃には、プログラムをおぼえるということは、この問題解決能力を磨くよい機会であるということがわかるだろう。 これこそが、この章を「プログラムのやり方」とした理由である。
プログラムをおぼえることは、そのこと自体便利な能力である。 しかし、別の考え方では、プログラムをおぼえることを、目的を達成するための手段とすることもできる。 本を読み進めていけば、この目的というものがより明確になっていくだろう。
これから学習していくプログラミング言語の名前はPythonといいます。 Pythonは、高水準言語のひとつです。 他の高水準言語として、C, C++, Perl, Javaといった名前を聞いたことがあるかもしれません。
低水準言語もあり、機械語や、アセンブリ言語が該当します。 大雑把に言うと、コンピュータは低水準言語で書かれたプログラムしか実行できません。 よって、高水準言語で書かれたプログラムは、実行する前に加工する必要があります。 この余計な加工を必要とする分だけ、高水準言語で書かれたプログラムは実行速度が遅くなりますが、その差は小さく、それほど不利とはならなりません。
一方、利点は非常に大きい。 まず、高水準言語では、プログラムが非常に簡単になります。 高水準言語でのプログラムは書くのにあまり時間がかからず、読む時間も短く、楽で、間違いも少ない。 また、高水準言語は「持ち運び」ができます。 つまり、他の種類のコンピュータで、ほとんど何の修正もなく実行できます。 低水準言語で書かれたプログラムは、あるひとつの種類のコンピュータでしか実行できず、他の種類のコンピュータで実行しようとするともう一度書きなおす必要がでてきます。
このような利点のために、ほとんど全てのプログラムは高水準言語で書かれています。 低水準言語は特別な目的のために使われるに過ぎません。
高水準言語で書かれたプログラムを、コンピュータが実行可能な低水準言語に変換する方法には2つの種類があります。 インタープリタを使う方法と、コンパイラを使う方法です。 インタープリタは、高水準言語を読み、実行します。 つまり、プログラムが書かれた通りに実行します。 インタープリタは、プログラムを一度に少しずつ読んで実行します。
一方コンパイラは、プログラムを実行する前に、全体を読み込み変換ます。 この意味で、高水準言語のプログラムはソースコードと呼ばれ、変換されたプログラムをオブジェクトコードあるいは、実行ファイルと呼びます。 プログラムがコンパイルされると、変換をやり直す必要はなく、何度でも実行することができます。
インタープリタを使うには2つの方法があります。 それは、インタラクティブモードと、スクリプトモードである。 インタラクティブモード(対話モード)では、Pythonのプログラムを入力すると、インタープリタがその結果を表示します。
>>>の記号は、プロンプトと呼ばれ、インタープリタの準備ができていることを示します。 1 + 1と入力すると、インタープリタはその結果の2を表示します。
プログラムをファイルに保存して、そのファイルの内容をインタープリタに渡して、実行させるという方法があります。 このとき、プログラムを保存したファイルをスクリプトと呼びます。 慣習的に、Pythonのスクリプトは、.pyで終わるファイル名を持ちます。
スクリプトを実行するには、インタープリタにそのファイル名を伝える必要があります。 UNIXのコマンドウィンドウでは、python dinsdale.py と入力してください。 他の環境では、スクリプトを実行する方法は異なります。 PythonのWebサイト(python.org)で、自分の環境に合った実行方法を探してください。
インタラクティブモードは、すぐに結果が出るので、コードの一部をテストするには便利ですが、数行を越えるコードになると、あとで変更できるようにスクリプトとして保存し実行すべきです。
プログラムとは、どのような計算を実行するのかを指定した、命令文が順番に並んだものです。 ここで計算とは、数学的な等式の解を計算するものでもいいし、多項式の解を見つけるものでもいいが、 文章の中から文字を探して別の文字に変換するものでもいい、(変だけど)プログラムをコンパイルするものでもいい。
プログラミング言語によって異なりますが、基本的な命令はほとんど全てのプログラミング言語に備えられています。
信じようと信じまいと、まさにその通りなのである。 あなたが使ったことのあるプログラムも、それがどんなに複雑であっても、ここで説明したような命令から出来上がっている。 よって、プログラミングとは、大きくて複雑な仕事を、基本的な命令で処理できるほどの小さな仕事にまで分解していくことであるといえる。
この説明はややあいまいだが、アルゴリズムを説明するときにもう一度説明する。
プログラミングには、エラーがつき物です。 変わった理由で、プログラムのエラーは、バグと呼ばれ、バグを探して修正することをデバッグと呼びます。
プログラミングの際に発生するエラーは次の3種類に分類されます。 文法エラーと、実行時エラーと、セマンティックエラー(内容的エラー)です。 これらのエラーは、デバッグの際に区別されます。
Pythonは、文法が正しい場合に限ってプログラムを実行できます。 文法的に正しくないとインタープリタは、エラーメッセージを表示します。 文法は、プログラムの構造と、構造についてのルールを参照ます。 たとえば、括弧は必ずペアで使われなければならず、(1 + 2)は文法的に正しいですが、8)は、文法的に間違っています。
英語がわかる人には、多くの文法エラーを許せるでしょうし、許せるからこそエラーメッセージを吐かずに詩歌を読むことができます。 しかし、Pythonは文法エラーを許しません。 プログラムにどこか一箇所でも文法エラーがあると、Pythonはエラーメッセージを表示し、プログラムの実行をやめてしまいます。 プログラミングを始めて最初の数週間は、文法エラーを探すことに多くの時間を費やすことになるでしょう。 慣れてくると、ミスをすることは少なくなるし、エラーがあってもすぐに見つけられるようになります。
エラーの種類の2つ目は、実行時エラー(ランタイムエラー)です。 これは、プログラムを実行しないと発見できないエラーなので、実行時エラーと呼ばれます。 実行時エラーは、「例外」とも呼ばます。 これは、実行時エラーが、例外的な処理をしようとした場合に発生することが多いからです。
小規模なプログラムでは、実行時エラーが発生することは少ないので、第1章で見ることはないでしょう。
エラーの種類の3つ目は、セマンティックエラーです。 セマンティックエラーは、プログラム中に含まれていても、(何のエラーメッセージも表示しないという意味で)プログラムは正常に実行されますが、 正しいプログラムではありません。 何か別のことを実行しています。 別のこととは具体的には、書かれた通りのことです。
問題は、書かれているプログラムが、書こうと思っていたプログラムと異なることです。 プログラムの内容(つまりプログラムのセマンティック)が間違っているのです。 セマンティックエラーを見つけることは、かなり難しいことです。 なぜなら、プログラムの結果を見て、プログラムが何をやっているのかを理解するという通常と逆の作業が必要となるからです。
プログラムの能力のうち最も重要な能力のひとつは、デバッグの能力です。 デバッグは面倒な仕事ですが、知的で、やりがいがあり、面白い部分でもあります。
デバッグは、探偵の仕事に似ている部分があります。 何らかのヒントから、目の前に表示されているエラーを引き起こしているプロセス、イベントは何なのかを推理する必要があります。
デバッグは、実験科学にも似ています。 何が間違っているのかの仮説が立った場合には、プログラムを修正して実行し仮説を確かめることができます。 もし、仮説が正しければ、修正した結果を予測することができるし、正しく動作するプログラムに一歩近づいたことになります。 仮説が間違っていれば、別の仮説を立てる必要があります。 シャーロックホームズが指摘したように、「不可能な可能性を排除していけば、残った可能性がどんなに有り得なさそうであっても、それが真実だ。」 (コナン・ドイル4つの署名より)
プログラミングと、デバッグは同じものだという人もいます。 どういうことかというと、プログラミングという作業は、作りたいプログラムが動作するまで少しずつデバッグしていくということであって、つまり、動作をする小さなプログラムの部品を作り、その部品の修正、デバッグをしていくことで、自然とプログラムが完成するということです。
例えば、Linuxは、数万行のコードにより作られているOSですが、 最初は、リーナス・トーバルズがインテルの80386というICを解析するための簡単なプログラムでした。 Larry Greenfieldによれば、「ライナスの初期のプロジェクトは、AAAAとBBBBの表示を切り替えるものでした。それが、最後にはLinuxにまで成長した。」(The Linux Users’ Guide Beta Version 1より) 後の章で、デバッグやプログラミングの手法については、さらに紹介しています。
自然言語とは、英語やスペイン語やフランス語のような、人間によって話されている言語のことをいいます。 自然言語は、(文法にルールを課す場合はあっても、)人間が設計したものではなく、自然と変化していくものです。
形式言語とは、何らかの目的のために人間によって設計されたものを指します。 例えば、数学の添え字のルールなどは、特に数字と記号の関係を示すのに便利な形式言語です。 化学者は、分子構造を表現するのに形式言語を用います。 プログラミング言語も特別な計算のために人間によって設計された形式言語です。
多くの形式言語は、その構文について厳格なルールを定めています。 例えば、3+3=6は、数学の文として数学的に正しですが、3+=3$6は数学的に間違っています。 H2Oは、化学的に正しいですが、2Zzは間違っています。
構文のルールにはふたつの側面がり、記号と、構造に関係します。 記号は、言語の基本的な要素で、単語や、数や、化学的な元素などです。 3+=3$6という文の、数学的な問題点のひとつは、$という記号が、数学において有効な記号ではないということです。(少なくとも私の知る限り) 同様に、2Zzの化学的に間違っている点は、Zzという略称をもつ元素がないことです。
構文エラーの種類のふたつめは、文の構造に関することです。 つまり、文の要素の並べ方です。 3+=3$6という文は、+と=がどちらも有効なトークンではあっても、間違った文である。+のすぐ後に=をつけてはいけません。 同様に分子式においては、数字は、添え字になり、元素記号の前にはつきません。
練習問題1 文法的に正しいが、有効でない記号を用いた英語の文章を書け。 それから、有効な記号を用いているが、文法的に正しくない文章を書け。 英語の文章であっても、形式言語であっても文章を読むときは、読むときは、 (自然言語の場合は無意識に行っているであろうが)文の構造を理解しなければならない。 このことをパースと呼ぶ。