Skip to content

Latest commit

 

History

History
432 lines (345 loc) · 42 KB

File metadata and controls

432 lines (345 loc) · 42 KB

Pythonインタプリタとスクリプトの体験、計算的思考

(任意) テキストエディタ CotEditor のインストール

テキストファイル編集のためのアプリを {index}テキスト・エディタ<てきすと・えでぃた-テキスト・エディタ>({index}text editor) と呼びます。授業ではテキスト・エディタ代わりにも使えるVSCodeを使います。エディタ毎の癖があるので、自分好みのものを探してみよう。


用語集

shell, prompt, command, statement, code, program, script, source

:name: w2-term1
用語集1

ターミナル上でアプリケーション(シェルやPython等)とやり取りを行う際、アプリ側が入力を受け付けられる状態か否かを明示するために用いられるのが {index}プロンプト<ぷろんぷと-プロンプト>({index}prompt) である。ターミナルを起動した直後の状態からプロンプトが出力される。具体的な命令を入力せずにEnterキーだけを入力すると、キーが入力される度にプロンプトが出力される。この「プロンプトが返ってくる」ことを通して、こちらの入力を受け付けているということが分かる。

ターミナルを起動した直後に出力されるプロンプトを、上記では「シェルのプロンプト」と書いている。これは、ターミナルを起動すると自動的に {index}シェル<しぇる-シェル>({index}shell) が起動され、実際に応答しているのはシェルだからだ。シェル上でpythonと命令を入力すると「{index}Pythonインタプリタ({index}python interpretor)」が起動し、プロンプトの出力形式が変わる。「>>> 」の状態ならPythonインタプリタが入力を受け付けている状態である。このようにプロンプトから「今何とやり取りしているのか」を意識しながら取り組もう。

なお後述するが、シェルやPythonインタプリタに対する入力は「{index}標準入力<ひょうじゅんにゅうりょく-標準入力>({index}standard input, {index}stdinと省略)」、逆に得られる出力を「{index}標準出力<ひょうじゅんしゅつりょく-標準出力>({index}standard output, {index}stdout」と呼ぶ。「標準」と付けている理由は、入出力をする経路が複数あるからである。例えば、ターミナルウィンドウを複数立ち上げているとしよう。それぞれのウィンドウでPythonインタプリタを起動している場合、それぞれのインタプリタはどのように入力を受け、またどのように出力したら良いだろうか。このような混乱をしなくて済むように、特に何も指定しなかった場合にはインタプリタを立ち上げたウィンドウを対象とするように紐付けられている。標準で用意されている入出力先のことを標準入力、標準出力と呼ぶ。

Pythonインタプリタが処理を実行する際の単位を {index}コマンド<こまんど-コマンド>や{index}命令<めいれい-命令>({index}command, {index}statement) と呼び、それらを集合を {index}コード<こーど-コード>や{index}プログラム<ぷろぐらむ-プログラム>、また{index}ソース<そーす-ソース>({index}code, {index}program, {index}source) と呼ぶ。また、コードやプログラムをファイルとして保存したものを {index}スクリプト<すくりぷと-スクリプト>({index}スクリプト・ファイル<すくりぷと・ふぁいる-スクリプト・ファイル>; {index}script file)、{index}ソース<そーす-ソース>({index}ソース・ファイル<そーす・ふぁいる-ソースファイル>; {index}source file と呼ぶ。文脈に応じて意味が異なることもあるが、他人とのやり取り中における「ソース見せて」という文は、「書いたコードを見せて」「保存したコードを見せて」と同等の意味で使われる。


operator, type, int, float, str, bool, variable, comparison

:name: w2-term2
用語集2

基本的な型、演算、type()関数で型を調べられることを覚えておこう。

==!={index}比較演算子<ひかくえんざんし-比較演算子>({index}comparison operator) と呼ばれており、演算子の左右が等しいか否かを確認するために用いられる。例えば「先着100人までプレゼントする」ようなコードを書こうとすると、応募のあったユーザを順番に並べて一人ずつカウントする。そのカウントした値を変数countに保存しておき、「count == 100」の比較結果が真であれば、100人分処理し終えたということを判断できる。比較演算子の結果は真偽のみであり、{index}True もしくは {index}False という {index}bool型({index}boolearn, {index}ブーリアン<ぶーりあん-ブーリアン>とも呼ばれる)のリテラルで返される。

bool型リテラルの ``True`` や ``False`` は、文字列ではない点に注意しよう。例えば、
```python
>>> True == 'True'
```
において、左辺はboolean型のTrue(真)というリテラルであり、右辺はstr型のリテラルである。異なるリテラルであるため、比較結果は False となる。

print()やtyp()のように、名称(引数) の形式で実行する命令を {index}関数<かんすう-関数>({index}function と呼ぶ。数学における関数の場合、例えば y = 2x + 1 という1次関数では、変数xの値を具体的に決めると出力yを算出することができる。この変数xに相当する部分、すなわち入力を指定する部分をプログラムでは {index}引数<ひきすう-引数>({index}arguments, {index}parameters と呼ぶ。

プログラムにおける関数は、引数で与えられる情報を元に、何かしらの処理を行う。具体的には、print()関数では「引数として与えられたリテラル、もしくは変数の中身を標準出力に書き出す」し、type()関数では「引数として与えられたリテラル、もしくは変数の中身の型を調べ、返す」という処理を実行する。関数は自身でも作ることが可能であり、後日取り扱う。興味のある人は教科書で予習してみよう。


comment, boolean

:name: w2-term3
用語集3

命令文に # が含まれていると、そこから行末までは {index}コメント<こめんと-コメント>({index}comment) として扱われる。コメントは人間がメモをしておくために用いる。また、一時的にコードを実行したくないが削除したくない場合に、コードの冒頭に#をつけることで該当行をコメントとして解釈させることもあり、このような行為は {index}コメント・アウト<こめんと・あうと-コメント・アウト>({index}comment out と呼ぶ。

>, >=, <, <= は {index}数値を用いた比較演算子<すうちをもちいたひかくえんざんし-数値を用いた比較演算子>である。「より大きい」「以上」のようにその値を含むのかどうかを区別できるようになろう。この使い分けを間違うと「100人に対しプレゼントする」つもりでも99人までしか処理できなかった、ということになる。よくあるミスであり、このようなミスを発見しやすくするための手法を境界テストと呼ぶ(後日やります)。

and, or, not{index}論理演算子<ろんりえんざんし-論理演算子>({index}boolean operator) と呼ばれており、左右のリテラルがbool型であることを前提として処理する。例えば「条件1も条件2も揃っているのでステージクリアと見做す」ような場合には and 演算子による確認が向いている。or, not についてもどういう用途がありそうか、考えてみよう。

``#``を含めるとその後ろがコメント扱いになることは既に述べたとおりである。では「#を含めた文字列」をstr型として用意したり、そのままprint関数で出力したりするにはどうしたら良いのだろうか。具体的には次のようなコードを書くと、どうなるだろうか。
```python
>>> statement = '朝早くて眠い #今授業中'
>>> print(statement)
```
答えは ``朝早くて眠い #今授業中`` が出力される。すなわち、#を含む文字列がそのまま後ろまで出力されており、コメント扱いになっていない。これは **{index}`優先順位<ゆうせんじゅんい-優先順位>`** の問題である。例えば数学における ``1 + 3 * 2`` の結果は8ではなく7である。これは足し算より先に掛け算が優先されるからだ。これと同様に、プログラムの記述には優先順位が定められている。今回のケースでは ``#`` よりも ``'`` による文字列定義が優先されているため、#がそのまま文字列として扱われていることになる。

同様に ``print(')')`` は、紛らわしいが ``)`` という1文字を文字列として扱い、それをprint関数が出力する。このように命令文の処理は予め指定された優先順位に従って処理されるということを覚えておこう。
```{tip}
上記で述べたように処理には順序が定められている。興味のある人は[公式ドキュメントの評価順序、優先順位](https://docs.python.org/ja/3/reference/expressions.html#evaluation-order)を眺めてみよう。
```
上記のコード例ではまず変数 statement を宣言して値を保存し、次にその変数の中身を出力している。このコードを書く際には1文字ずつ全てを手打ちする必要はなく、**{index}`Tabキーによる入力補完`** を利用すると良い。{index}`Tabキー`とは Controlキーの上にある右矢印が印字されているキーのことだ。

入力補完をやってみよう。まず1行目はそもそもまだコンピュータが見知らぬ変数なので、そのまま手打ち入力する必要がある。2行目は ``print(s`` まで入力した状態でTabキーを1〜2回押してみよう。1回目は通知音のようなものがなるだけだが、2回目は次のように出力されるはずだ。
```python
>>> statement = '朝早くて眠い #今授業中'
>>> print(s
set(           slice(         statement      str(           super(
setattr(       sorted(        staticmethod(  sum(           
>>> print(s
```
上記は「sから始まる変数もしくは予めPythonで用意されている関数」の一覧が表示された結果である。続けて ``print(state`` まで入力した状態でTabキーを押してみよう。そうすると自動的に ``print(statement`` まで入力した状態になるはずだ。このように、頭文字1文字以上を入力した状態でTabキーを押すと、そこから推測できる文字列の一覧を示したり、もしくは一意に定まる場合には最後まで入力してくれる機能のことを入力の自動補完と呼ぶ。全ての変数名や関数名を一文字も間違えないようにこわごわ入力するのではなく、補完機能を使えばスムーズに入力できることを覚えておこう。

文字列結合

2週目授業ではひとまずスキップし、最後に時間ありそうなら改めて説明する。

>>> enemy = 'スライム'
>>>
>>> # case 1: 出力したい文字列を1変数に用意してからprint()する。
>>> output = enemy + 'が2体現れた'
>>> print(output)
スライムが2体現れた
>>>
>>> # case 2: print()内で演算処理する。
>>> print(enemy + 'が2体現れた')
スライムが2体現れた
>>>
>>> # case 3: str.format()形式を利用する。
>>> output = '{}が2体現れた'.format(enemy)
>>> print(output)
スライムが2体現れた
>>> print('{}が2体現れた'.format(enemy))
スライムが2体現れた
>>>
>>> # case 4: f-string形式を利用する。
>>> output = f'{enemy}が2体現れた'
>>> print(output)
スライムが2体現れた

ここでは文字列結合の例を4つ示している。

1つ目は、文字列を保存した変数に対して文字列リテラルを結合している例である。

2つ目は、引数内に演算子が含まれるケースを示している。このように演算子が含まれる場合、演算子がなくなるまで演算を実行し、その結果を引数として利用する。

3つ目は、とても見づらいがPython特有の文字列作成方法である。いくつか新しい要素が出てきているため、分解して考えてみよう。

  • (1) '{}が2体現れた' は、str型の文字列を表している。 試しに '{}が2体現れた' のみを引数として指定した場合には、そのまま出力されるはずである。
  • (2) (1)の後ろに続く .format(引数) は、直前の文字列における {} を引数に置き換えた文字列を生成する。これを{index}str.format形式と呼ぶ。 例えば、
>>> '{}'.format(1)

は、{}を数字の1に置き換えた文字列を生成する。

>>> '{}'.format(enemy)

は、変数enemyが何か値を保存しているならば、その中身を{}の部分に置き換え、文字列を生成する。

>>> '{}が{}体現れた'.format(enemy,2)

は、1つ目の{}を変数enemyの中身に置き換え、2つ目の{}を数字の2に置き換えた文字列を生成する。

4つ目は、str.format形式を簡略化した{index}f-string書式({index}フォーマット済み文字リテラル<ふぉーまっとずみもじりてらる-フォーマット済み文字リテラル>を用いている。

このような一見複雑に見える文字列結合の手段を用意しているのは、単に +演算子による結合を用いた場合にわかりづらくなったり、変数の中身(型)に応じて文字列結合の書き方が異なるためだ。例えば分かりづらい例としては、

>>> '1+1' + 'は' + '2' + 'です'

というコードを人間が見たとき、どの部分がリテラルなのかは直感的には分かりづらい。これに対し、

>>> '{}+{}は{}です'.format(1,1,2)

であれば、3つのリテラルがあること、そのリテラルを組み合わせた文字列を生成したいという意図を汲み取りやすい。 このように「人間にとっての読みやすさ(リーダブルコード, readable code)」の観点から、str.format()形式や f-string が提供されている。

現時点で細かな差異を覚えておく必要はないが、[f-stringはPythonバージョンによってサポート範囲(利用できる記述)が異なる](https://docs.python.org/ja/3.10/reference/lexical_analysis.html#formatted-string-literals)点に注意しよう。想定通りの動作をしない場合には公式ドキュメントで確認するようにしよう。

スクリプトの利用

スクリプトとは?

ここまでは、Pythonインタプリタを起動し、そこでコードを直接書くことで命令をコンピュータに伝え、実行させていた。しかしこの方法では、同じ命令をさせたい場合にはその都度同じコードを書く必要があり、手間である。この手間を省くため、コードをテキストファイルに保存して実行する方法がある。この「コードが保存されたファイル」のことを {index}スクリプト<すくりぷと-スクリプト>や{index}ソースコード<そーすこーど-ソースコード>({index}script, {index}script file, {index}source code,,,) と呼んでいる。

スクリプトとしてコードを保存する際には、{index}テキスト・エディタ<てきすと・えでぃた-テキスト・エディタ>({index}text editor) を使おう。テキストエディタとは、テキストのみを編集(edit)してファイル保存するためのソフトである。プログラミングにおいては「プログラミング言語仕様に則ったコード」をそのままテキストとして保存する必要があるため、テキストに特化したソフトを使う。テキストエディタには色んな種類があり、それぞれ癖があるので、いろいろ試してみることで使いやすいものを後日探してみるといいだろう。


スクリプトを書いてみよう

今回は VSCodeを テキスト・エディタ代わりに使い、以下の手順でスクリプトを書いて動かしてみよう。なお、ここではターミナル操作の演習を兼ねて (1) テキスト・エディタで保存したスクリプトをターミナルで実行する、(2) VSCodeで直接実行する、の2種類の実行方法を試してみましょう。

ところで、ファイルが散らかってしまうと探しにくくなります。これを避けるため、プログラミング1で利用するファイルを保存するための作業用ディレクトリとして ~/prog1 を作成することにしましょう。

  • 補足
    • ~/チルダ、スラッシュ と発音し、実行したユーザ自身のホームディレクトリ を示すために用いる表記である。このフォルダやディレクトリとはOS毎に呼び名が変わるだけで、基本的には同一のものと考えておこう。
    • あなたが使っているPCは、初めてセットアップした際にあなた専用のアカウントを作ったはずだ。これは複数のアカウントを作ることが出来る(例えば家族で共用して使うとか)。その際に各アカウント毎に「ここは私専用のフォルダ」「あそこはあなた専用のフォルダ」といったことを決めておいた方が使いやすい。各自のフォルダをホームディレクトリと呼ぶ。
    • 例えば當間のアカウントは tnal で作成しており、PC上のホームディレクトリは /Users/tnal/ である。この / はルートディレクトリと呼ばれており、ルートディレクトリから対象ディレクトリまでのパスを全て羅列する書き方を フルパスや絶対パス(full path, absolute path) と呼ぶ。一方で ~/~/Downloads/ のように、ルートディレクトリ以外を基準とした書き方を 相対パス(relative path) と呼ぶ。

step 1: スクリプトを保存する場所を用意する。

では、実際に作業用ディレクトリを作成してみましょう。

  • step 1-1: ~/prog1 を作成するためには、まずターミナルを起動しよう。
    • この時点でホームディレクトリにいる。このことを確認するためには pwdコマンド (print working directoryの略) を入力し、実行する(Enterキーを押す)と良い。
    • 今いるディレクトリ上にどのようなファイルがあるかを確認するためには、lsコマンド (listの略) を入力し、実行しよう。
  • step 1-2: 次に、ターミナル上で mkdirコマンド (make directoryの略) を使い、prog1ディレクトリを作ろう。
    • 具体的には mkdir prog1 と入力し、実行する。
    • 正しく作成されたことを確認するために、lsコマンドを実行してみよう。出力される一覧の中に含まれていることを確認しよう。

これで作業用ディレクトリを用意することができました。以降の作業はこのディレクトリに移動してから作業していくことになります。ディレクトリを移動するためには cdコマンド (change directoryの略) を使い、次のように実行します。

  • step 1-3: cd prog1 と入力し、実行する。
    • ディレクトリを変更(移動)できたことを確認するため、pwdコマンドを実行してみよう。
    • また、新規作成したばかりのディレクトリには何もファイルがないことをlsコマンドで確認してみよう。

step 2: 作業ディレクトリでVSCodeを起動する。

ターミナルからVSCodeを起動すると、カレント・ディレクトリを開いた状態で作業環境を用意してくれる。

  • step 2-1: VSCodeを起動する。
    • code . と入力し、実行する。
      • codeコマンドは、VSCodeアプリを起動するためのコマンドである。
      • . は、「今いるディレクトリ」を指している。code . で「今いるディレクトリを作業ディレクトリとして起動する」と解釈して起動してくれる。

VSCodeの画面説明

:name: vscode-leftmenu
VSCodeの左パネル

上図は、VSCodeを立ち上げたばかりの状態だ。基本的には左側のアイコンから操作するか、もしくはこの図には表示していない上部メニュー(VSCodeを前面にしている状態での、アプリ画面の外にある最も上部にあるメニュー)から操作することになる。

macOSでは、林檎アイコンがある最上部のメニューは固定されておらず、操作アプリに依存してメニューが変化する。例えば、VSCodeで操作している(前面にしている)状態で上部メニューを確認すると ``Code`` となっている。ターミナルを前面にすると、``ターミナル`` に変わることを確認してみよう。

また、Welcome(和訳されているなら「ようこそ」)タブが開いており、大きな文字で Start, Recent が列挙されていると思う。ただし Recent は過去に開いたディレクトリを表示している(直前に開いた場所は、改めて開くことが多いため)ので、初めて起動した際には何も表示されていないだろう。

:name: vscode-newfile
VSCodeでExplorerを開いた状態

上図は、Explorerを選択してファイル一覧を表示した状態だ。左パネルに一覧が表示されており、當間の環境では過去に利用したファイルをまとめたディレクトリが列挙されている。

この左パネルから New File を選択し、ファイル名を test.py として確定しよう。確定するには Enter キーを押すと良い。

:name: vscode-test
VSCodeでtest.py編集する状態

上図は、新規にtest.pyという名前のファイルを作成した状態である。右側上部が編集エリアになっており、テキストやプログラムを書くために利用する。右側下部にはターミナル画面が表示されており、プログラムの実行や実行結果を表示するために利用することが多い。通常のターミナル(macOS標準のターミナルアプリ)と同じことができると考えてもらって良い。


step 3: 作業ディレクトリで作業する。

実際にコードを書いて保存しよう。具体的には、新規ファイルとして test.py を作成し、print('こんにちわ')というコードを書いて、保存しよう。保存するためには上部のFileメニューからSaveを選ぶか、もしくはショートカットキーを利用して {index}⌘+s(⌘を推しながらs)でも保存(save)することができる。

  • 注意点
    • 日本語と英語の入力モードに伴い、入力される文字が変わることに注意しよう(参考: Wikipedia:全角と半角
    • 例えばprint(1)print(1)は異なる。前者は全てを半角英数字で入力しているのに対し、後者は「1」と「)」が全角だ。
      • このうち「全角の1」は、プログラムを処理するインタプリタにとっては文字として処理しようとする。しかしながらPythonでは文字列はシングルクォートかダブルクォートで囲う必要がある。その結果、文字に見えるが文字ではない(クォートで囲われていない)ため、{index}SyntaxError となる。SyntaxErrorとは、文法上誤っているために実行できないことを意味している。
    • 類似した例として print(1)print(1) も異なる。後者は最後の丸括弧が全角になっている。
{index}`catコマンド`を使い、``cat test.py``というようにファイル名を指定してターミナルで実行すると、test.pyの中身を確認することができます。ターミナルとVSCodeはアプリは異なりますが、同一ディレクトリで作業しています。例えばターミナル上でvimコマンドを使ってテキストファイルを編集する個が可能ですが、保存し終えると、自動的にVSCode側で開いている中身が更新されます。

コードの説明

print('こんにちわ') というコードは、print関数とその引数('こんにちわ')の組み合わせになっており、「こんにちは」という文字列を出力するように動作する。良くある誤りとして、以下に示すような書き方では同じ結果が得られないことに注意しよう。

コード 異なる点
print(こんにちは) クォートで囲っていない。なお、この場合には NameError となる。
print('こんにちは) 左側だけクォートがついている。SyntaxError
primt('こんにちは') 関数名が違う。NameError
print('こんにちは' 左側だけ丸括弧がついている。SyntaxError
「print関数」における関数とは、数学における関数に似ているためにプログラムにおいても呼称として使っている。

数学における関数、例えば ``f(x) = x + 1`` を考えると、この関数fに対してx=10を入力として与えると、``f(10) = 10 + 1 = 11`` となり、11という結果を得られるはずだ。つまり、数学における関数とは、ある変数に依存して値が決まる式や操作のことを指している。

これに対してプログラミングにおける関数とは、前述の関数fのようなものが予め多数用意されており、それを利用するためには ``関数名(引数)`` という書式でプログラムを書くことになる。すなわち、``print('こんにちわ')`` とは、print関数に対して文字列「こんにちは」を指定して実行してくれ、という意味になる。関数のより詳細な話は後日扱う。

スクリプトの実行(case 1: ターミナルで実行する)

とても重要なことが一つあります。ターミナル上で実行する際には 必ず、実行する前にファイルを保存する ことを忘れないようにしましょう。保存しない限りファイルには何も書かれていないか、もしくはエディタ上で見えるものとは異なる内容(古い内容)が保存されています。この状態でターミナルから実行すると、古い内容を参照してしまうため、いくら正しいコードを書いていたとしても想定した結果を得ることができません。

ターミナルから実行するには次のようにします。

  • (1) ファイルを保存する。
  • (2) ターミナル上で、プログラムを保存したディレクトにいることを確認する。
    • 例えば pwdコマンド や lsコマンド で確認することができる。(何故だろう?)
  • (3) ファイル名を指定して、次のように入力し、実行する。
    • python ファイル名
    • 今回は test.py を実行したいので、python test.py と入力し、実行することになる。
ターミナル上ではシェルと呼ばれるプログラムとの対話形式で処理をすすめることになります。シェル上では``コマンド名 引数1 引数2 ...``という形式でコマンドを引数付きで実行することができます。

引数は必ずしも指定する必要はなく、例えば ``python`` と実行するとPythonインタプリタが起動し、直接Pythonのコードを1行ずつ実行して動作確認することができるようになります。Pythonインタプリタを終了するには ``exit()`` と入力して実行するか、もしくは {index}`Ctrl+d`(コントロールキーを推しながらd)を入力します。

コンピュータが返す出力を読み取る

特に何も問題なく実行でき、想定通りの結果が得られる場合にはそれでプログラミング終了(プログラムの完成)となります。しかし何かしら不具合がある場合には、実行できるが結果が異なったり、実行そのものができなかったりします。このような場合には (a) 何をどのように実行したのか、(b) どのような結果が得られたのか、を意識しながら問題点を探っていくことになります。

ターミナル上で実行する際に良くある典型的な誤りには、(1) コマンド名のミス、(2) 引数のミスがあります。

例えば、pythonコマンドを実行するつもりで、意図的に誤って pyton を実行してみてください。「{index}zsh: command not found: pyton」という出力が返ってくるはずです。これは「pytonコマンドを実行しようとしたが、見つからなかった」ということをユーザに伝えています。

次に引数を誤る例として python test2.py を実行してみてください。「{index}python: can't open file '/Users/tnal/prog2/test2.py': [Errno 2] No such file or directory」という出力が返ってくるはずです。大分長いですが、「test2.pyというファイルをpythonコマンドで実行しようとしたが、そのファイルを開くことができなかった。指定したファイルは見つけられなかった」ということをユーザに伝えています。

最初から全てのエラー出力を理解する必要はありませんし、初めてなので普通はわからないでしょう。エラー文が返ってきた際にはまず英文そのものを直訳してみて、どのようなエラーなのかを想像してみると良いでしょう。もし想像できない場合には、TAや教員、先輩学生らに相談してみましょう。人に相談するのもとても大切なスキルですので、相談する練習だと思ってどしどし相談ください。

なお、人によってはエラーが帰ってくることそのものに忌避感を感じてしまうこともあるようです。しかし、コンピュータは人とは違い、どれだけ誤った入力をしたとしても根気強く付き合ってくれます。人にはない優れた点ですので、気にせず使うことをおすすめします。

スクリプトの実行(case 2: VSCodeで実行する)

VSCode上で実行するのはとても簡単です。編集画面右上にある ボタンをクリックすると、その時点で開いているファイルを保存し、実行してくれます。実行結果はVSCode内のターミナル・パネルに表示されます。


スクリプトファイル vs. インタプリタ

:name: w2-interpretor-vs-script
スクリプトファイル vs. インタプリタ

慣れてくると最初からVSCodeを使った開発が早いが、言語仕様に慣れていない段階ではいろいろと細かく試しながら確認できるインタプリタの方が便利なことも多い。例えばVSCodeとターミナルの2つを立ち上げておき、インタプリタで納得できるコードが書けたらそれをVSCodeにコピーして保存するとか、双方の利点を使い分けるといいだろう。


変数名・ファイル名の命名規則(教科書にない内容)

:name: w2-naming
命名規則

変数名やファイル名として使うことの出来る文字と、規約を覚えておこう。冒頭3項目はPythonの言語仕様としてのルールであり、厳守する必要がある。

その次の Level3〜Level4、Google Python Style Guide は規約の例、言い換えるとローカルルールである。言語仕様を守っただけの変数名では分かりにくい名称が使われることも多く、読みにくいコードになることがある。例えば四角形の面積を求めるために、

>>> area = height * width

と、

>>> a = b * c

とではどちらがコードの意図を汲み取りやすいだろうか。1つ目は意図の汲み取りやすいコードとなっており、その分バグを発見しやすくなるため保守しやすい。現場ではコードを一度書いて終わりではなく、何度も修正・機能追加等を伴う編集をしながら使い続けていくため、読みやすさを意識したコードが望ましい。そのためにも組織毎にローカルルールを定め、それに則る名称を利用することが一般的である。多くの場合に共通するLevel2ぐらいまでを意識して名付けるようにしてみよう。


マニュアルの参照(教科書にない内容)

  • Python公式ドキュメント
  • help()関数 on Pythonインタプリタ
    • 例: >>> help(print)
  • Google先生
    • e.g., 「python print」 or 「python3 print」
    • できるだけ複数単語で検索し、絞り込む。単に「print」だと、別のプログラミング言語のページがヒットしたり、「配布資料(プリント)」のことがヒットする可能性。単一単語では判別困難。
  • 注意
    • Python 2 <-> Python 3で異なることがある。
    • Web上の情報は間違ってることがある。

関数に関するドキュメントは、公式ドキュメントから探すか、直接Pythonインタプリタ上でhelp()関数を使うと参照することができる。例えばprint()関数について調べると以下のような出力が得られるはずだ。

>>> help(print)
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
  (中略)
(END)
  • 上記の print(value, ..., sep=' ', 略) は使い方を簡易的に示している。ENDでマニュアルの最後であり、マニュアル画面から抜け出してインタプリタに戻りたい場合には、q(quitの頭文字) を入力しよう。
  • value はリテラルや変数を記述する欄であり、それらをカンマ(,)で区切って列挙できることを「value, ...,」として示している。
  • その次の sep=' ' は、数行下に説明があり「string inserted between values, default a space.」とある。これは、value欄に複数の値を列挙した場合、それらの値を何らかの文字を挿入することをしめしている。例えば、
>>> print(1,2,3)

の結果を確認してみよう。自動的にスペースが挿入された状態で指定した値が出力されるはずだ。このように「特に指定しなかった場合に自動で使われる値」のことを {index}デフォルト値<でふぉるとち-デフォルト値>もしくは単に{index}デフォルト<でふぉると-デフォルト>({index}default) と呼ぶ。今回の場合にはスペースがデフォルト値として指定されているため、スペースが挿入されて出力されたことになる。パラメータsepを変更するには以下のように指定しよう。

>>> print(1,2,3,sep='#')
関数に与える引数は順序に注意しよう。``print(1,2,sep='#',3)`` のように書いても正しく処理できない。この点は関数について学ぶ時に改めて振り返ることにする。

end は、出力後に自動で追加される制御文字である。'\n' はこれで1文字の制御文字であり、「改行文字」を意味する。改行文字をsepとして設定するとどうなるだろうか。試してみよう。

Flush は通常無視して構わない。補足しておくとこれはコードの実行速度も考慮した話であり、四則演算と比べると「標準出力に書き出す」という処理はとても遅い。このため、print文が大量にあると全体として処理が遅くなってしまうが、通常はなるべくその負荷が小さくなるような工夫がなされている。逆にこの工夫のために、出力し終える前に別のコードの影響でプログラム全体が異常終了してしまうことがある。このような状況を避けるため、必ず出力し終えてから次に進むように指定するのがflushである。

計算的思考(教科書1章の補足)

:name: w2-chap1
計算的思考

左の宣言的知識で述べている平方根の定義は、定義として正しい。しかしこの定義からは平方根を求めることはできない。

右の命令的知識で述べているレシピ・手順・手続きは、平方根を求めるための手続きとして書き下されており、近似的な平方根を求めることが可能。このように 十分に定義された入力が与えられ、有限個の命令群で用意された手続きにより出力を求めることができる手続き のことを {index}アルゴリズム<あるごりずむ-アルゴリズム>({index}algorithm と呼ぶ。より詳細は2年次の必修講義「アルゴリズムとデータ」にて学ぶ。ここでは「入力と出力を明確にし、それをどのように処理するのかという手続きを考える必要があること」ぐらいを心に留めておこう。


翻訳に至る3ステップの例

1週目にプログラミングには3つのステップ(理解・整理・翻訳)があることを述べた。ここでは具体例を上げてその流れを説明する。

例として、「授業を担当している先生が、受講生に対して質問をするためにランダムに一人を選びたい」と考えているとしよう。すなわち Step 1の「実現したいこと」は「受講生の中から1名をランダムに選ぶ」 である。

さて、これを実現するために必要な手順 はどうなるだろうか。例えば次のように考えるかもしれない。この時点では誤っていても良く、取り敢えず可能性がありそうな手順として整理してみることに集中しよう。

  • (1) 受講生一覧を用意。
  • (2) 一覧をシャッフルする。
  • (3) シャッフルされた一覧から、先頭の一人を抜き出す。

ここで もし「受講生一覧の用意」の翻訳の仕方が分からない場合には、それをさらに細分化 して考えていこう。例えば次のようになるだろう。

  • (1-1) 受講生は学生記番号で区別されている。だから学籍番号で準備することを考えよう。
  • (1-2) 2022年度の知能情報コースの学籍番号は必ず 2257 から始まり、下二桁が入学者数と一致している。すなわち 225701〜2257xx の数字を用意することができれば、「受講生一覧の用意」をしたことになる。

最後にこれをプログラミング言語で翻訳することになる。例えばこうなるだろう。

students = list(range(225701, 225760))
import random
random.shuffule(students)
students.pop()

上記はまだ教えていない部分があるが、流れとしてはこのように、理解したことを手順として整理し、プログラミング言語で記述できるレベルまで細分化する。最後にコードに落とし込む という手順を取る。

プログラミングの過程において、もし手順に誤りがあったとわかればその時点で修正したら良いし、翻訳時点で誤りがあった場合にも同様にその時点で修正したら良い。思いつく方法を試し、修正しながらゴールに辿り着く力こそが重要である。だからこそ本授業ではいわゆるテストはせず、時間にゆとりを持つ形で取り組めるよう課題で評価する。
プログラミングは道具であり、コンピュータさえあればどこでも何でも(メモリ不足等でなければ)実現することができる。失敗を恐れず試行錯誤する術を学ぼう。

振り返り

:name: w2-summary
まとめ

復習・予習

  • 復習
    • 適宜過去資料及び教科書を参照しよう。
  • 予習
    • 教科書読み
      • 2.2 Branching Programs
      • 2.3 Strings and Input
    • 余裕があれば
      • 2.4 Iteration
      • (3章スキップ)
      • 4.1〜4.1.1 Function Definitions