Pythonエンジニア認定基礎試験の勉強してたら、意外と知らないことがあった件

# はじめに
[Python 3 エンジニア認定基礎試験](https://www.pythonic-exam.com/exam/basic)受けてきました。
勉強してたら知らないことがちらほらあったのでまとめてみました。

# プロフィール
- 社会人5年目
- プログラミングは大学の授業からやり始めて9年目
- Pythonやる前はCとJavaがメイン

# どんな勉強したか

- 「模擬試験→間違えたところ調べる→コード書いて動かしてみる」を何回かやった
- 勉強期間は1週間ほど
- 模擬試験は[ExamApp](https://python-basic.com/)、[DIVE INTO EXAM](https://diver.diveintocode.jp/dive_into_exam/lp)、[PRIME STUDY](https://study.prime-strategy.co.jp/)を使用
- 間違えたところはまず[Python チュートリアル](https://docs.python.org/ja/3.10/tutorial/index.html)読んでみる
- チュートリアルがわかりづらかったらネット上で記事探して補助してもらう
- 調べたものを書いて結果を`print()`で出力してみる（こういうときはコピペ、入力補助使わないのが個人的にはおすすめ。）

チュートリアル読むだけとかだと1分でおやすみなさいする人なので、なるべく手を動かしました。

ちなみに模擬試験のサイトは[Python初心者によるPython3エンジニア認定基礎試験の勉強方法（2020年8月合格）](https://qiita.com/gomasa/items/a0c91cea24f41fd63c1c)で知りました。教材から当日の状況まで、分かり易くまとめられています。

# 知らなかったこと
さて本題。今回勉強中に出会って「へぇ～」ってなったやつです。
こんなん知ってるわ！ってところは読み飛ばしてくださいね。

## スライス
[3.1.2 文字列](https://docs.python.org/ja/3.10/tutorial/introduction.html#strings)のところにしれっと書いてあったのですが、、、
```python
str_py = "PythonTutorial"
print(str_py[-1000:1000])
```
```
PythonTutorial
```
__範囲外でスライスしてもエラーにならない。__
もちろん`str_py[1000]`とかやると`IndexError`です。
プログラミングしてる時は便利だけど、問題で出されると戸惑うやつ。

## rangeの型
[4.3 range()関数](https://docs.python.org/ja/3.10/tutorial/controlflow.html#the-range-function)から。
`range()`の型ってわかりますか？
```python
r = range(5, 15, 3)
print(type(r), r)
```
`range`の型は**range**です。
正直、`list`だと思ってました。。。
```
<class 'range'> range(5, 15, 3)
```
これは知らんかった。
チュートリアルの[rangeのリンク](https://docs.python.org/ja/3.10/library/stdtypes.html#range)とぶと、`class range`って書いてありましたね。もう忘れない。（活かせる場面無さそうだけど。笑）

## ループのあとのelse
[4.4 break文とcontinue文、ループにおけるelse節](https://docs.python.org/ja/3.10/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops)から。
`for`のあとに何が書けるかみたいな問題で、「そんなんあったっけ？？？」ってなりました。
（ここはチュートリアルにある素数判定のコードを。）

```python
for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, 'equals', x, '*', n//x)
            break
    else:
        print(n, 'is a prime number')
```
`for`と`while`のあとに`else`書けるんですね。CとかJavaでは見たことないぞ？
```
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
```
ループ最後まで回りきったときに`else`に入って、
`break`で抜けた時は`else`には入らないとな。なるほど。

## enumerate
[5.6 ループのテクニック](https://docs.python.org/ja/3.10/tutorial/datastructures.html#tut-loopidioms)から。
（ここに書いてあるやつ、いつでも役立ちそうだから覚えておくべき！！！）

知らん単語出てきた！って感じでしたが、これは知っててもいいはずでしたね。。。

```python
seq = ['a', 2, 'b', 1, 'cd', 0.3]
print(list(enumerate(seq)))
```
`enumerate()`で**インデックス番号と要素**を取得できます。
```
[(0, 'a'), (1, 2), (2, 'b'), (3, 1), (4, 'cd'), (5, 0.3)]
```
これなら`for`でインデックス番号と要素両方扱うのが楽になりますね。
インデックス番号でいちいち指定しなくてよくなる。
```python
for i, data in enumerate(seq):
    print(i, data)
```
```
0 a
1 2
2 b
3 1
4 cd
5 0.3
```
他の言語やってた人はインデックス番号で`for`回しがちですよね。（言い訳）

## [zip](https://docs.python.org/ja/3.10/library/functions.html?highlight=%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF#zip)
[5.6 ループのテクニック](https://docs.python.org/ja/3.10/tutorial/datastructures.html#tut-loopidioms)からあと二つほど。
これももっと早く知っときたかったやつ。
```python
seq1 = ['a', 2, 'b', 1, 'cd', 0.3]
seq2 = ['A', 20, 'B', 10, 'CD', 0.03]
print(list(zip(seq, seq2)))
```
`zip()`で**複数のリストの要素**をまとめて取得できます。
```
[('a', 'A'), (2, 20), ('b', 'B'), (1, 10), ('cd', 'CD'), (0.3, 0.03)]
```
これで`for`もスッキリ書ける。Python便利。
```python
for data1, data2 in zip(seq1, seq2):
    print(data1, data2)
```
```
a A
2 20
b B
1 10
cd CD
0.3 0.03
```

## items
もう一つ、[5.6 ループのテクニック](https://docs.python.org/ja/3.10/tutorial/datastructures.html#tut-loopidioms)から。
辞書型を`for`で回す時に便利な`items()`。
```python
dic = {"a": 1, "b": 2, "c": 3, "d": 4}
print(list(dic.items()))
```
`items()`で**辞書型のキーと値**を同時に取得できます。
```
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
```
一つ目がキー、二つ目が値です。
`for`で使うとこんな感じ。
```python
for key, value in dic.items():
    print(key, value)
```
```
a 1
b 2
c 3
d 4
```
ちなみに`keys()`でキーだけ、`values()`で値だけが取り出せます。
冷静に考えればわかるけど、選択肢に三つ並んでると自信なくなるやつ。

## random
[10.6 数学](https://docs.python.org/ja/3.10/tutorial/stdlib.html#mathematics)から。
こいつら、どう違うかわかりますか？
- `random.random()`
- `random.randint()`
- `random.uniform()`
- `random.choice()`

普段から使ってないと覚えてないやつですよね。
|メソッド名|機能|
|:-|:-|
|`random.random()`|0.0以上1.0未満の浮動小数点を返す|
|`random.randint(a, b)`|a以上b以下の整数を返す|
|`random.uniform(a, b)`|a以上b以下の浮動小数点を返す|
|`random.choice(seq)`|与えたシーケンスの中から要素を1つ返す|

初心に戻って、下のコード何回か実行して遊んでました。笑

```python
import random

random_random = random.random()
print(type(random_random), random_random)

random_randint = random.randint(1, 10)
print(type(random_randint), random_randint)

random_uniform = random.uniform(1, 10)
print(type(random_uniform), random_uniform)

seq = ['a', 2, 'b', 1, 'cd', 0.3]
random_choice = random.choice(seq)
print(random_choice)
```
実行結果の例。
```
<class 'float'> 0.8565668866682062
<class 'int'> 2
<class 'float'> 3.0892644087182597
<class 'str'> b
```

## おまけ
一回引っかかったのが、問題文中のプログラムの構文エラー。
`SyntaxError`が選択肢にあったら、構文合ってるかまず確認するのがいいかも。
`if`とか`for`のあとに`:`無いとか。
普段は開発ツールたちが教えてくれますからね、意外と見てない。（言い訳②）

# まとめ
個人的に知らなかったことまとめてみましたが、`for`文で使うやつ中心になっちゃいましたかね。
まだCとかJavaの頭なのかも。。。
まあ今回勉強しなかったら永遠に知らなかったかもしれないので、いい機会でしたね！
普段書いてるプログラムも見やすくできそう。
気が向いたら実践試験も受けてみようかなぁ・・・。気が向いたら。

これから受験する方のお力に、少しでもなれてたら嬉しいです！
読んでいただきありがとうございました！

# 参考文献
[Python 3 エンジニア認定基礎試験](https://www.pythonic-exam.com/exam/basic)
[Python チュートリアル](https://docs.python.org/ja/3.10/tutorial/index.html)
[Python初心者によるPython3エンジニア認定基礎試験の勉強方法（2020年8月合格）](https://qiita.com/gomasa/items/a0c91cea24f41fd63c1c)
[ExamApp](https://python-basic.com/)
[DIVE INTO EXAM](https://diver.diveintocode.jp/dive_into_exam/lp)
[PRIME STUDY](https://study.prime-strategy.co.jp/)