プログラミング演習I
スライド
- 第1回 hello, world
- 第2回 上から、順番に。
- 第3回 (瀬尾先生担当回)
- 第4回 型・変数・入力・if
- 第5回 (瀬尾先生担当回)
- 第6回 繰り返し
- 第7回 (瀬尾先生担当回)
- 第8回 int, str (型変換)
- 第9回 リスト
- 第10回 (瀬尾先生担当回)
- 第11回 リストとfor
- 第12回 (瀬尾先生担当回)
- 第13回 スライスと再帰
いろいろ
Pythonは初学者向け?
自分が勉強したときも、学生に教えているときも強く感じた(ている)のですが Pythonって巷で言うほどプログラミング初学者には向いていないと思います。 個人の感想にはなってしまいますが、似たような言語としてはRubyの方が 遥かに初心者に優しいなと思うんです。以下、ぼくが思うPythonの初学者 泣かせな部分を書いていきます。
インデントは読みやすくても書きづらい
インデントは何かのはずみ(うっかり[TAB]や[スペース]に触れるとか、 コピペしたときとか) で簡単に挿入されたり脱落したりします。それでエラーになれば問題ない のですが、文法的にはエラーにならずロジックだけが変わってしまうことが ふつうにあります。例えば
i = 0
while i < 10:
print(i)
i += 1
ここのi += 1
のインデントが脱落しても文法的には正しいのに、実行時に
無限ループに突入します。
Ruby みたいにキーワード(begin–end)や、Cみたいに記号({})であればよほど
変な誤編集をしなければ単純な文法エラーとして検出可能です。また、
キーワードや記号だったら例えば最初に if () {}
と書いて
(お茶でも飲んで一服して)あとから
カッコ内をゆっくり穴埋めできるのですが、インデントだとそれができず、
その節を曲がりなりにも完成させるまで目を離せません。
構造が複雑になると自分の立ち位置を見失ってしまうことも多々あります。
そんなわけでインデントに文法的な意味を持たせるのはあまり良くないなぁと
思います。
けっきょくインデントが素晴らしいのは読みやすいところに尽きます。
……ですが、そうです。
RubyでもCでも、読みやすさのためにインデントをつけることは一般的に
行われています。(しかもPythonと違って機械的にきれいなインデントまで
可能、と。)
使い回し多すぎ
- 「if節の
if
」と「条件式(3項演算子)のif
」と「リスト内包のif
」とか、 - 「for文の
in
」と「リスト内包のin
」と「in
演算子」とか、 - 「
is
演算子」と 「is not
演算子」とか、 - 「
in
演算子」と 「not in
演算子」とか、
文法的に別モノ
なのに同じ単語を当てることが多いような気がします。確かに
英語として読みやすいかも知れないけれど初学者が3項演算子のif
を見て
路頭に迷うことは想像に固くありません。(“python if"で検索しても
上位には絶対出てこないだろうし。)
重要な記号 =
も、代入文で使う一方でキーワード引数でも使い回しています。
my_func(a=3)
を見て、Cプログラマーが頭を抱える姿は容易に
想像できます。(Pythonの =
による代入は 文であって式ではない、
ということを知らない初級〜中級者はきっとハマります。)
熟語の演算子
具体的にはis not
と not in
演算子ですが、これ、
スペース込みで熟語ひとカタマリの演算子 なんです!(知ってました?)
別にいいじゃん、って思うかも知れませんがさにあらず。まさか熟語だとは
思ってもいない、でも is
と not
はそれぞれ知っている中級者が
1 is not None
という式を見たらどう思うでしょう?
1 is (not None)
と解釈しそうですよね? ところが間違い。単に
解釈の間違いだけでなく値も変わってしまいます。前者は True, 後者は False です。
関係演算子の連鎖
まるで数学みたいに if 0 < x < 79:
と書けるのがPythonの良いところ……
では全然ないと思います。これって、『"<
“は数値と数値を真理値に変換する
(左結合の)演算子である』という常識的な理解をもとに、if (0 < x) < 79:
と読もうとすると全く意味がわからなくなります。一見数学みたいで初心者に
優しいと思うかも知れませんが、実は全く逆で、基本から応用を演繹しようと
する努力を打ち砕く、アタマの中に言語モデルを構築しにくい仕様に思えて
なりません。(ぼく自身、Python勉強したての頃真剣に悩みました。)
端的には下記のようなことが起こります。結果が変わるだけでもややこしい
のですが、話を余計にややこしくしているのは2行目がエラーでなく
False なこと。これについては次項で。(次回更新時にでも)
print(-1 < 0 < 1) # -> True
print((-1 < 0) < 1) # -> False