プログラミング入門(Python)のTAやってて思う初学者の傾向

本記事は，[DSL Advent Calendar 2019](https://qiita.com/advent-calendar/2019/muroran-it-dsl)の8日目の記事です．

この記事はどちらかというとプログラミング教育者向けのレポート的なものかもしれません．
また，特定の人や団体の批判をしようとしている訳ではないので，そちらだけご理解いただけると助かります．

今年から室蘭工業大学全学科の学部一年生にプログラミング入門という講義が始まりました．この授業ではプログラミング言語「Python」を用いてプログラミングやデータ処理を体系的に学んでいく内容となっております．演習では[国立情報学研究所(NII)](https://www.nii.ac.jp)が提供している Jupyter Notebook を用いています．また，授業毎に演習と課題をそれぞれ1枚ずつ.ipynbを配布し一問一答形式で問題に取り組んでもらっています．

その講義に私はTA(Teaching Assistant)として参加しています．その中で気がついたプログラミング初学者がPythonを学ぶ時に特に躓く点などを紹介していけたらなと思います．この記事を見た同じ立場の人や教員の方が役立ててくれるといいなと思います．

## よくあるミスの原因
1. 全角で入力している
1. インデントブロックを意識できない
1. 型を意識できない
1. エラーの内容が読めない

これらについてどんな間違いをしているのか，どんな対策を取れば良いのか例を上げながら紹介していきます．

### 全角で入力している
#### 例

- 全角スペース
- 記号や括弧などを全角で入力してから変換 (かっこ→（）など)

プログラミング初心者につきものなのがやはり全角入力です．全角スペースが入っているとエラーが出てしまうのでプログラムは動かなくなってしまいます．また，Pythonは全角文字であってもstrとして簡単に使えてしまうので注意が必要になってきます．特に気をつけるべきなのは基本全角で入力している人です．特に現代はスマホ世代とも言われている様にプログラミングというよりキーボード入力に不慣れな人もそれなりにいます．そうなると記号の場所が分からないというのも分からなくない話だと考えられます．

#### 解決策
- PCキーボードに慣れてもらう
- 全角入力が必要ない様な問題文にする

この解決策はやはりキーボードに慣れてもらうことが一番だとは思います．その他にはいっその事，問題自体を全角入力が必要のない問題にしてしまうのが良いのかもしれません．(例えば日本語の文章を出力していた箇所を全て英語にしてしまうとか)


### インデントブロックを意識できない
#### 例
よく見かけたのがこんな間違いです．

```python
for i in range(10):
    for j in range(10):
    print(f'i + j = {i + j}')  # エラー: インデントがズレている
```

本来ならば`print()`でもう一つインデントを下げなければいけないのですが，正しく下げられていません．上記のような2重for文ならそこまで間違いはないのですが，さらにifなどの条件分岐が入ってくるなど，ネスト構造が増えていくとより間違いが増えていく印象です．

これを助長させるのがプログラムのコピペやjupyterのオートインデント機能です．プログラムのコピペといっても他人のプログラムを引っ張ってくるというより，問題設計として前の問題の一部を使って次の問題に取り込むみたいな場合の方が多くの人が躓いてる印象です．例えば，1問目で条件分岐だけ作って2問目でforループの中にそれを組み込む様な問題だとオートインデント機能でネスト構造が狂いエラーで動かないということがあります．その他にもインデントを複数のスペースで取っているとどんどん構造が理解できなくなっているパターンも見かけます．

#### 解決策

- ネスト構造を理解すること
- Tabキーでインデントを取ること
- エラーを読むこと

この3点で大抵何とかなると思っています．PythonはC言語などと違い，ループが括弧でなくインデントで制御されているので特にネスト構造に注意が必要です．そのためどんなプログラムにせよインデントの重要性をまず教えていくことが大切になってきます．また，Tabキーを使うことで補完機能やインデント作業を若干楽にできるので早めに使い方を教えていくこともこの問題の解決には重要だと思っています．そしてエラーを読むことが何よりの解決方なのですがどこがどう狂っているのかはコードによっては分からないのでやはり構造の理解の方が必須だと思います．

### 型を意識できない
#### 例
こちらはこんな間違いです．

```python
# パターン1
a = 1
b = "1"
print(a + b)  # エラー: int + str はできない
print(a + int(b))  # 2

# パターン2
a = (1, 2, 3)
b = [1, 2, 3]
a.append(4)  # エラー: タプルにappendはできない
b.append(4)  # [1, 2, 3, 4]
```

パターン1はプログラミング初心者によくあるやつなのですが，Python以外の言語だと型宣言してから変数を宣言するのでPythonが初めて学ぶプログラミング言語の場合は特に気を付けなければいけない点だと思います．またパターン2についても同様のことで，aはタプル・bはリストなのですがこれらの「配列」に要素を増やしたい時appendを用いるのですが，プログラミング初心者の場合，配列がリストであれタプルであれ(辞書であれ)おおよそ同じものに見えてしまうみたいです．

#### 解決策

- type() を用いて型確認を行う
- 型毎のメソッドや性質の違いを明確にしておく
- エラーを読むこと
- typing モジュールを使って型を明示的に宣言する

型の難しい話は分からないのでアレなのですが，Pythonでは基本的に分からない変数などの型はtype()で確認するのが早いのでよしなに．また，型毎の違いを理解していれば上記の様な事にはならないはずなので教える時に詳しく時間をかけると良いのかもしれません．そしてこちらもエラーを読む事で解決できるので，やはりエラー表示は偉大ですね．後はtypingモジュールについてです．これはPythonの環境にも依存しますが，この使い方だけでもまた一記事ほどかけてしまいそうなので詳しい説明は省略しますが，typingモジュールを使うとより型が意識できる様になるかもしれません．


### エラーの内容が読めない
こちらは特に例を出すことが難しいので少しばかり解決策を提案できればと思います．
またエラーが読める様になるだけで上で挙げた問題の殆どは解決できるはずなので，これが一番大事なのかもしれません．

#### 解決策
- 予め予想されるエラーの文章とその解決策をまとめておく
- エラーの内容をそのままWeb検索する習慣をつけておく

この2点が簡単にできそうなことだと思います．エラーの内容は同じ問題を解いている以上，ほとんどの人は同じところで躓くことが多いと考えられます．そのため予め予想されるエラー内容とその対処法をまとめておくと良いかと思います．またWeb検索という事についてですが，やはりプログラミング初心者はエラーをググるという習慣がありません．Pythonであればほとんどのエラーはそのままエラー文をコピペして検索した結果を真似るだけで解決できる問題がほとんどなので，そういった習慣をつけたほうが楽なのかもしれません．


## その他問題が解けない原因
ここからはミスの原因というより教材やjupyterを使っているから起こるミスだと思われるものを軽く挙げたいと思います．これは教える側も教えられる側も同様にjupyterの仕様を把握することで簡単に解決できる問題だと思います．

1. Jupyterのcellでエラーが出なければ正解だと勘違いしている
2. 問題が複数cellに分かれていて想定通りの結果にならない

### Jupyterのcellでエラーが出なければ正解だと勘違いしている
現在提供されているJupyter Notebook環境ではcellを実行する時，エラーが出なければ緑，エラーだと赤の表示が出ています．基本的には全て緑の表示が出れば問題ないのですが，それが逆に進行の妨げになっている場合もあります．例えば，関数のみを定義したセルでは中身の挙動が多少おかしくてもエラーは表示されないので問題なくcellが実行できます．そのため，下部のcellでその関数を用いて何かしらの処理をしてエラーが出た時どこを見れば良いのか分からない，という様な問題も発生します．

### 問題が複数cellに分かれていて想定通りの結果にならない
この問題は私の大学が講義で配布しているipynbに纏わる問題で，上の問題とも関わりが深い問題なのですが，問題が複数cellに分かれていて実行した時の挙動がおかしくなるというものです．例は下の画像を参考にしてください．

![スクリーンショット 2019-12-08 4.53.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153871/4c556f7a-1178-6bb0-2445-44ff892adecd.png)

上の様にそれぞれの問題が上のcellの実行結果に依存した問題になっていると，挙動が怪しくなる場合があります．上の例では，q1,q2で作成したリストと関数を用いてq3を問いていますが，実際にはもっと複雑な処理や問題となることもあります．これの何が問題かというと，cellの実行順序が上から下としか想定されていない事です．これにより再度実行すると既存の出力とは違う結果が出力されることがあります．また，serverエラーなどでnotebookの応答がなくなった時，カーネルのリスタートが必要になることがあるのですが，cellの途中からしか実行していない人も多くいます．(これは，再起動で変数なども全てリセットされていることを理解していないため)

このjupyterの仕様が中々厄介なので，これを解決するためにやはり一つの問題は一つのセルにまとめてしまうのが無難かと思います．


## まとめ
簡単にPythonのプログラミング入門のTAをやっていて思ったことを挙げてみましたが，案外教える側の配慮が足りていなかったため躓いていることが多くある印象でした．あまり長々と書いてきたのも疲れたのでここらへんで一旦筆を置こうと思いますが，実際にはもっと些細な点で躓きが発生しているのでやはりプログラミングを教えるというのは難しいものだなと感じました．この記事が誰かの助けになればと思います．