【Python】エラーメッセージの内容を理解する（２）

#### 背景

自身がPython習得をすすめる上での備忘録ではありますが、エラーメッセージの読み解き方を、ここにまとめておきます。
前回、掲載しきれなかったエラーを掲載した『第二弾』です。

- 第一弾　[【Python】エラーメッセージの内容を理解する](https://qiita.com/_whitecat_22/items/60e9b5b9f9809afa1fe8)

先人たちの知恵をお借りするなどして解決できたことを、この場をお借りして感謝するとともに、大変恐縮ですが自分のメモとしても、こちらへまとめておきます。

#### 開発環境

- Windows 10 Pro
- Python 3.9.0, 3.8.5
- Django 3.1.3
- PostgreSQL 13.1
- Nginx 1.19.5
- Gunicorn
- Putty 0.74


# エラーメッセージ

## 9. ImportError

- `from <モジュール名> import <オブジェクト名、関数名 など）>
` でモジュールに含まれていないオブジェクトをインポートしようとした場合などに発生する。大文字・小文字も区別されるため、タイプミスに注意。

```python:python
from bs4 import BeautifulSoap    # 誤...Soap→Soup

from bs4 import BeautifulSoup    # 正
```

```:ターミナル
ImportError: cannot import name 'BeautifulSoap' from 'bs4' (/usr/local/～/python/3.9.0/・・・)
```

【訳】
import（取り込み）Errorが発生：「bs4」から「BeautifulSoap」という名前のモジュールを取り込めません。
　↓
**『「BeautifulSoap」って名前のモジュールが取り込めないよ～！』**ということ。

※綺麗な石鹸（Soap）じゃなくて、<font color="orange"><b>美味しいスープ（Soup）</b></font>ですよ～！^^

＜注＞
モジュール名やオブジェクト名は正しいか、対象のモジュールにそのオブジェクトが含まれているかは、公式ドキュメントなどを確認する癖を付けましょう
稀にライブラリがバージョンアップされた際に、そのオブジェクト名が変わったり、無くなったり（廃止されたり）します

## 10. IndexError

- リストやタプルなどシーケンスオブジェクトに格納された値を `[インデックス]` で取得する際、その範囲外の位置（要素数を超えたインデックス値）を指定することで起こる。

```python:python
list1 = ["あ", "い", "う", "え", "お"]

print(list1[5])        # 誤...末尾の "お" は、インデックスでは [要素数-1] であるため、4 と指定するのが正解

print(list1[4])        # 正
# お
```

```:ターミナル
IndexError: list index out of range
```

【訳】
IndexErrorが発生：リストの索引は範囲外です。
　↓
**『リスト型の索引の範囲外だよ～**（...だから探しに行けないの...）**』**ということ。

　
リストやタプルの要素数は `len()` 関数で確認可能です。よく確認してからインデックスを指定しましょう。
ちなみに、インデックスは `0` から数えはじめますので、末尾は `要素数－1` 番目になります。

```python:python
list1 = ["あ", "い", "う", "え", "お"]

print(len(list1))
# 5
```

## 11. KeyError

- 辞書型（dict型）の値をキー指定して取得する際、存在しないキーを指定してしまうと起こる。

```python:python
dict1 = {1 : "りんご" , 2 : "みかん", 3 : "ぶどう" , 4 : "バナナ"}

print(dict1[5])    # 誤...'5' は、Key として存在しない

print(dict1[4])    # 正
# バナナ
```

```:ターミナル
KeyError: 5
```

【訳】
KeyErrorが発生：'5'（が、キーエラーです。）
　↓
（そのまま）**『5 は キーエラーですな～』**ということ。

　
キーの一覧は、`keys()` メソッドで確認しましょう。

```python:python
dict1 = {1 : "りんご" , 2 : "みかん", 3 : "ぶどう" , 4 : "バナナ"}

print(dict1)
# {1: 'りんご', 2: 'みかん', 3: 'ぶどう', 4: 'バナナ'}

print(list(dict1.keys()))
# [1, 2, 3, 4]
```

　
**裏技？**
`get()` メソッドを使うと、存在しないキーに対してもエラーになりません。
この場合、デフォルト値を取得することができます！


```python:python
print(dict1.get[5])

# None
```

辞書に含まれるキーや、指定したキーが正しいかを、よく確認しましょう。
（指差し確認、安全よーし！！）

## 12. AttributeError

- 属性（Attribute）の参照に関して起こる。

「<オブジェクト>.<識別子>」のようにメソッドなどを呼び出す際、オブジェクトや識別子（属性やメソッド）の名前、オブジェクトの型を間違えた場合に発生する。
大文字・小文字も区別されるため、タイプミスに注意。


#### 12-1.

- 識別子の名前を間違えた例：

```python:python
import math

print(math.PI)        # 誤...PI→pi

print(math.pi)        # 正
```

```:ターミナル
AttributeError: module 'math' has no attribute 'PI'
```

【訳】
AttributeErrorが発生：'math' モジュールは 'PI' という属性を持ち合わせません。
　↓
**『「math」は「PI」なんて、持ってないってさ！』**ということ。

#### 12-2.

- オブジェクトの型が想定と違った例：

```python:python
counter = 60

counter.append(120)
```

```:ターミナル
AttributeError: 'int' object has no attribute 'append'
```

【訳】
AttributeErrorが発生：'int' オブジェクト（数値型オブジェクト）は 'append' という属性を持ち合わせません。
　↓
**『数値型オブジェクトに「append」なんて、備わってないってよ～』**ということ。


オブジェクト名、識別子名や、オブジェクトの型は想定通りか、をよく確認しましょう。


## 13. FileNotFoundError

- ファイルを読み込む際など `open()` で指定したファイルが見つからないときに起こる。

```python:python
with open('sample1.txt') as f:    # sample1.txt は存在しない
    print(f.read())
```

```:ターミナル
FileNotFoundError: [Errno 2] No such file or directory: 'sample1.txt'
```

【訳】
FileNotFoundErrorが発生：'sample1.txt' というファイルまたはディレクトリはありません。
　↓
**『「sample1.txt」 は ありまへんがな～』**ということ。

　
指定したファイルやディレクトリは本当に存在している？
指定したパスは正しい？特に、相対パスで指定したときのカレントディレクトリは正しい？
（相対パスで指定した際、Pythonのカレントディレクトリが想定と異なっている可能性も考えられます。）


## 14. FileExistsError

- ファイルやディレクトリを作成しようとした際に、それが既に存在したときに起こる。（13.の逆パターン）

```python:python
import os
os.mkdir('sub_dir')        # 'sub_dir' は既に存在している
```

```:ターミナル
FileExistsError: [Errno 17] File exists: 'sub_dir'
```

【訳】
FileExistsErrorが発生：'sub_dir' というファイル（またはディレクトリ）は存在します。
　↓
**『「sub_dir」 は もう在るやん！』**ということ。

指定したファイル（またはディレクトリ）はすでに存在していない？

＜注＞
python 3.2.x 以降では、`os.makedirs()` に引数 `exist_ok` が追加されています。
このため、`exist_ok=True` とした際には、既に存在しているディレクトリの作成を試みてもエラーとなりません。


---
#### (編集後記)

よく遭遇するエラーを集めてまとめてみました、の第二弾です。
エラーの内容、原因・理由を理解して、複雑なプログラミングをする際に、エラーが出ても慌てないようすることと、対処を適切に素早く施せるようにしたいですね。

VS Code には、リアルタイムに文法をチェックしてくれる拡張機能もあるようですので、いろいろ試してみようと思います。