[Python] AttributeError: module ‘json’ has no attribute ‘loads’ 錯誤

簡介

在這篇文章中,我們會探討 Python 中的 AttributeError: module 'json' has no attribute 'loads' 錯誤為何會出現以及應該如何解決,事不宜遲,讓我們嘗試重現這個錯誤吧!

重現這個錯誤

  1. 創建一個稱為 json.py 的 Python 程式,這只是一個從一條 string 中讀取 json 資料的簡單程式。

json.py

#!/usr/bin/env python3

import json

sample_json =  '{ "name":"John", "age":30}'
data = json.loads(sample_json)

print(f'{data["name"]} is {data["age"]} years old...')
  1. 運行 json.py 這個程式,轟!我們已經成功把錯誤重現了!
noob@learnfromnoobs:~$ ./json.py 
Traceback (most recent call last):
  File "json.py", line 1, in <module>
    import json
  File "/home/noob/json.py", line 4, in <module>
    data = json.loads(sample_json)
AttributeError: module 'json' has no attribute 'loads'
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
  File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
    from apport.report import Report
  File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module>
    import apport.fileutils
  File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module>
    from apport.packaging_impl import impl as packaging
  File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 18, in <module>
    import json
  File "/home/noob/json.py", line 4, in <module>
    data = json.loads(sample_json)
AttributeError: module 'json' has no attribute 'loads'

Original exception was:
Traceback (most recent call last):
  File "json.py", line 1, in <module>
    import json
  File "/home/noob/json.py", line 4, in <module>
    data = json.loads(sample_json)
AttributeError: module 'json' has no attribute 'loads'

我們可以怎樣處理這個錯誤?

如果你只想盡快處理這個錯誤,而又不在意這個錯誤背後的原因的話,你只需要把你的程式改為 json.py 以外的名字。

例如,

noob@learnfromnoobs:~$ mv json.py json_test.py
noob@learnfromnoobs:~$ ./json_test.py
John is 30 years old...

如果錯誤在改名後依然存在,可能是因為你在 json.py 旁邊產生了 json.pyc 這個檔案,我們需要把這檔案刪除,否則 json.pyc 仍然會被讀取,令錯誤繼續出現。

那背後其實發生了甚麼事?

要理解到底是甚麼造成這個錯誤,我們先要理解 import 是怎樣運作的。

當我們 import 一個模組時,Python 會先尋找我們指明的模組,再把模組載入,它會用 sys.path 來嘗試尋找模組,看看能否在 sys.path 中的位置內找到模組,我們在 Python interactive shell 中看看 sys.path 儲著甚麼吧。

noob@learnfromnoobs:~$ python3
Python 3.6.8 (default, Oct  7 2019, 12:59:55) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']

sys.path 包含 Python 尋找模組的位置,留意當前位置(current working directory)在 sys.path 中是以空白字串(”)來表示的。

根據有關 sys.path 的官方文件sys.path 的第一個位置是程式的存在位置,由於剛剛我們只是在 interactive shell 中進行實驗,並沒有程式位置,sys.path 的第一個位置則變成了空白字串,表示 Python 會先在當前位置尋找模組。

在我們的例子中,我們把程式稱為 json.py ,同時我們嘗試 import json 模組,由於 json.py 的存在位置是 sys.path 中的第一個位置,Python 會首先在 json.py 的存在位置尋找模組,當然,因為這樣,Python 會找到錯誤的模組,在我們的的 json.py 中並沒有 ‘loads’ 這個 attribute,導致 AttributeError: module 'json' has no attribute 'loads' 這個錯誤的出現。

總結

我們在這篇文章中討論了為何 AttributeError: module 'json' has no attribute 'loads' 這錯誤會出現,為甚麼我會知道?我必須要承認我在進行簡單實驗太過懶惰了,直接把程式名為 json.py,但這是個不錯的體驗,亦是個有趣的分享,記得不要使用模組名作為程式的名稱,否則你會再遇到這些錯誤。

注意在這篇文章,我們大幅簡化了 Python 的 import 過程,如果你想知道更多有關 Python 的 import 過程,請參閱 有關 import 的官方文件.

我希望你喜歡這篇文章,並從中得到新知識。

記得要不斷學習,have fun!

Leave a Reply

Your email address will not be published. Required fields are marked *