
作者|Chad Hansen
來源|Python學習開發
英文|Understanding the Python Traceback – Real Python
在寫 Python 代碼的時候,當代碼中出現錯誤,會在輸出的時候打印 Traceback 錯誤信息,很多初學者看到那一堆錯誤信息,往往都會處于懵逼狀態,腦中總會冒出一句,這都是些啥玩意。如果你是第一次看到它,也許你不知道它在告訴你什么。雖然 Python 的 Traceback 提示信息看著挺復雜,但是里面豐富的信息,可以幫助你診斷和修復代碼中引發異常的原因,以及定位到具體哪個文件的哪行代碼出現的錯誤,所以說學會看懂 Traceback 信息是非常重要的,另外在面試的時候也經常會問到 Python 中的異常類型及其含義,那么,接下來就讓我們對其進行詳細理解。
什么是 Traceback
Traceback 是 Python 錯誤信息的報告。在其他編程語言中有著不同的叫法包括 stack trace, stack traceback, backtrac 等名稱, 在 Python 中,我們使用的術語是 Traceback。后面我提到的錯誤信息等詞都表示Traceback。
當你的程序導致異常時,Python 將打印 Traceback 以幫助你知道哪里出錯了。下面是一個例子來說明這種情況
# example.py def greet(someone ): print('Hello, ' + someon ) greet('Chad')
這里首先定義了函數 greet,然后傳入參數 someone,然后函數內,一個 print 語句其中 someon 是一個沒有定義的變量,
然后通過 greet ('Chad'),調用剛才定義的 greet 函數,運行之后會出現如下錯誤信息。
(Python 中的錯誤信息開頭就是 Traceback。)
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 5, in <module> greet ('Chad') File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 3, in greet print ('Hello, ' + someon ) NameError: name 'someon' is not defined
此錯誤輸出包含診斷問題所需的所有信息。錯誤輸出的最后一行一般會告訴你引發了什么類型的異常,以及關于該異常的一些相關信息。錯誤信息的前幾行指出了引發異常的代碼文件以及行數。
在上面的錯誤信息中,異常類型是 NameError,意思是名稱使用了一個沒定義的名稱(變量、函數、類)的引用。在本例中,引用的名稱是 someon。
一般情況下看錯誤信息的最后一行就能定位到錯誤的原因。然后在代碼中搜索錯誤提示中的名稱"someon",然后發現這是一個拼寫錯誤,然后我們改成 someone 即可。
然而,有些代碼的錯誤信息要比這個復雜的多。
如何閱讀 Python 的 Traceback 信息?
當你想確定代碼為什么引發異常的時侯,可以根據 Python 的 Traceback 獲取許多有用的信息。下面,將列舉一些常見的 Traceback,以便理解 Tracebac 中包含的不同信息。
Python Traceback 信息一覽
每個 Python 的 Traceback 信息都有幾個重要的部分。下圖顯示了各個組成部分:
一個具體的
通過一些特定的 Traceback 信息,可以幫助我們更好地理解并查看 Traceback 將提供什么信息。
通過下面的示例代碼來說明 Python 中 Traceback 所提供的信息
def who_to_greet(person ): return person if person else input ('Greet who? ') def greet(someone, greeting='Hello'): print(greeting + ', ' + who_to_greet (someone )) def greet_many(people): for person in people: try: greet(person ) except Exception: print ('hi, ' + person )
定義一個 who_to_greet 函數,然后接受一個值 person,并根據 if 判斷返回相應結果。
然后,greet 函數接受一個 someone 和一個可選的 greeting,之后調用 print 函數,在 print 中調用 who_to_greet 函數并傳入參數 someone。
最后,greet_many(),將迭代 people 列表并調用 greet 函數。如果通過調用 greet()引發異常,則會打印一個簡單的問候語。
只要提供了正確的輸入,此代碼就沒有任何可能導致異常被引發的錯誤。
如果你在 greetings.py 中調用 greet 函數,并傳入值(例如 greet ('chad',greting ='Yo')),那么你將獲得以下 Traceback 信息
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/greetings.py", line 17, in <module> greet ('chad',greting ='Yo') TypeError: greet () got an unexpected keyword argument 'greting'
之前我們說過閱讀 Python 的 Traceback 信息,是由下而上進行閱讀的,這里我們再一起看一看。
首先,我們需要看的是錯誤信息的最后一行,通過最后一行可以知道錯誤的類型以及一些錯誤原因。
意思是說:調用 greet()的時候使用了一個未知的參數,這個未知參數就是 greting。
好的,然后我們需要繼續向上看,可以看到導致異常的行。在這個例子中我們看到的是調用 greet 方法的具體代碼。
它的上一行提供了代碼所在文件的路徑,以及代碼文件的行號以及它所在的模塊。(Pycharm 中通過點擊文件鏈接可以定位到具體位置)
在這個例子中,因為我們的代碼沒有使用任何其他 Python 模塊,所以我們在這里看到<module>,它表示所處位置是在執行的文件。
使用不同的文件和不同的調用方式調用 greet 方法,得到的 Traceback 信息也是不同的,下面就通過文件導入的形式來執行 greet 方法??纯唇Y果有什么區別吧
# example.py from greetings import greet greet (1)
運行之后的結果
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 3, in <module> greet (1) File "/Users/chenxiangan/pythonproject/demo/greetings.py", line 6, in greet print (greeting + ', ' + who_to_greet (someone )) TypeError: can only concatenate str (not "int") to str
在本例中引發的異常同樣是一個類型錯誤,但這一次消息的幫助要小一些。它只是告訴你,在代碼的某個地方,字符串只能和字符串拼接,不能是 int。
向上移動,可以看到執行的代碼行。然后是文件和行號的代碼。不過,這一次我們得到的不是,而是正在執行的函數的名稱 greet()。
然后繼續往上看,一行執行的代碼,我們看到問題代碼是 greet()函數調用時傳入了一個整數。
有時在引發異常之后,另一部分代碼會捕獲該異常并導致異常。在這種情況下,Python 將按接收順序輸出所有異常信息,最外層的異常信息處于 Traceback 內容的最下面位置。
可能看起來有點懵,下面使用一個具體例子進行說明。
在 greetings.py 文件中調用 greet_many 方式具體調用代碼如下:
greet_many (['Chad', 'Dan', 1])
運行之后輸出的錯誤信息如下
Hello, Chad Hello, Dan Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/greetings.py", line 12, in greet_many greet (person ) File "/Users/chenxiangan/pythonproject/demo/greetings.py", line 6, in greet print (greeting + ', ' + who_to_greet (someone )) TypeError: can only concatenate str (not "int") to str During handling of the above exception, another exception occurred: Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/greetings.py", line 17, in <module> greet_many (['Chad', 'Dan', 1]) File "/Users/chenxiangan/pythonproject/demo/greetings.py", line 14, in greet_many print ('hi, ' + person ) TypeError: can only concatenate str (not "int") to str
emmmmm,這次好像不太一樣,比之前的內容多了不少,而且有兩個 Traceback 塊信息,這是什么意思呢?
注意這句話
During handling of the above exception, another exception occurred:
它的意思是:在處理上述異常期間,發生了另一個異常。簡單理解就是在 except 中的代碼出現了異常。所以導致了這種現象。
這個例子就是在第三次循環的時候 person=1 然后字符串 hi 和1 不能進行拼接操作,然后再次引發了異常。
查看所有的錯誤信息輸出可以幫助您了解異常的真正原因。
有時,當您看到最后一個異常被引發,并由此產生錯誤信息時,
你可能仍然看不出哪里出錯了。比如這例子,直接通過最后的異??床坏絾栴}具體出在哪,這個時候就要考慮繼續往上看了。
Python 中有哪些常見的異常類型
在編程時,知道如何在程序引發異常時讀取 Python 異常信息非常有用,如果再了解一些常見的異常類型那就更好了。
有時候在面試的時候也會遇到提問 Python 中常見的異常類型,以及其含義,所以這里也建議大家都了解以下。
下面就列舉一些出現頻次高而且非常重要的異常類型,希望大家能夠有一定的印象。
AttributeError
當你訪問一個對象的屬性,但是這個屬性并沒有在這個對象定義的時候,就會引發 AttributeError。
下面是一個引發 AttributeError 異常的示例:
a = 1 a.b
運行之后引發異常
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 2, in <module> a.b AttributeError: 'int' object has no attribute 'b'
AttributeError 的錯誤消息行告訴我們特定對象類型(在本例中為 int)沒有訪問的屬性,
在這個例子中屬性為 b。點擊文件鏈接可以快速定位到具體的錯誤代碼的位置。
大多數情況下,引發這個異常表明你正在處理的對象可能不是你期望的類型。
a_list = (1, 2) a_list.append (3)
運行之后拋出異常信息
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 2, in <module> a_list.append (3) AttributeError: 'tuple' object has no attribute 'append'
這里嘗試給 a_list 對象進行 append 操作但是引發了異常,
這里的錯誤信息說,tuple 對象沒有 append 屬性。
原因就是以為 a_list 是列表但是實際上它是元組,
元組是不可變類型不支持添加元素操作所以出錯了。這里也告訴大家,以后定義變量名的時候也要主要規范問題,否則就容易出現這種,期望類型錯誤的情況。
還有一種情況就是當對 None 進行屬性操作的時候,很容易引發上面的異常
a_list = None a_list.append (3)
運行拋出異常
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 2, in <module> a_list.append (3) AttributeError: 'NoneType' object has no attribute 'append'
是不是很眼熟啊,遇到這種情況不要慌,分析看看你的哪個對象是 None 就好了。
ImportError
在使用 import 導入模塊時,如果要導入的模塊找不到,或者從模塊中導入模塊中不存在的內容。這時就會觸發 ImportError 類型的錯誤或者它的子類 ModuleNotFoundError。
import aaa
運行后輸出
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 1, in <module> import aaa ModuleNotFoundError: No module named 'aaa'
在這個例子中可以看到,當我們使用 import 導入一個不存在的模塊時,就會出現 ModuleNotFoundError 的錯誤,Traceback 最下面一句信息給出了原因,
沒有名為 aaa 的模塊.
然后我們再運行一個例子
from collections import asdf
運行之后的內容
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 1, in <module> from collections import asdf ImportError: cannot import name 'asdf' from 'collections'
根據前面的經驗我們可以得知原因,不能從 collections 模塊中導入名為 asdf 的模塊。
有時候為了程序能兼容在各個系統的時候,如果一個包找不到,找另一個的時候,比如在 windows 中不能使用 ujson ,uvloop這兩個包,但是在 unix 系統上是可以運行的,這個時候我們就可以使用下面的方法。
try: import ujson as json except ImportError as e: import json
首先導入 ujson 然后使用 as 給他重命名為 json,如果出現錯誤就會進入 except 模塊
然后導入標準庫的 json 包,因為這邊的庫名已經叫 json 了所以不用再重命名了。記住這個技巧非常的有用哦。
IndexError
當你嘗試從序列(如列表或元組)中檢索索引,但是序列中找不到該索引。此時就會引發 IndexError。
例如
a_list = ['a', 'b'] a_list[3]
運行之后的結果
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 2, in <module> a_list[3] IndexError: list index out of range
通過 IndexError 的錯誤消息的最后一不能得到一個準確的信息,只知道一個超出范圍的序列引用以及序列的類型,在本例中是一個列表。我們需要往上閱讀錯誤信息,才能確定錯誤的具體位置。這里我們得知錯誤代碼是 a_list[3]原因是索引3 超出了列表的范圍,因為最大就是1(索引下標從0 開始的)。
KeyError
與 IndexError 類似,當你訪問映射(通常是 dict )中不包含的鍵時,就會引發 KeyError。
a_dict={} a_dict['b']
運行之后
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 2, in <module> a_dict['b'] KeyError: 'b'
KeyError 的錯誤消息行給出找不到關鍵字 b。并沒有太多的內容,但是,結合上面的錯誤信息,就可以解決這個問題。
NameError
當你引用了變量、模塊、類、函數或代碼中沒有定義的其他名稱時,將引發 NameError。
def greet (person ): print (f'Hello, {persn}') greet ('World')
運行之后
Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 3, in <module> greet ('World') File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 2, in greet print (f'Hello, {persn}') NameError: name 'persn' is not defined
NameError traceback 的錯誤消息行給出了缺失的名稱 persn。
這個例子中,在 print 使用了沒有定義過的變量 persn 所以出現了錯誤。
一般在拼寫變量名出現問題時會引發這種錯誤。
SyntaxError
當代碼中有不正確的 Python 語法時,就會引發 SyntaxError。
下面的問題是函數定義行末尾缺少一個冒號。
def greet (person )
運行之后
File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 1 def greet (person ) ^ SyntaxError: invalid syntax
SyntaxError 的錯誤消息行只告訴你代碼的語法有問題。查看上面的行才能得到問題所在的行,通常會用一個^(插入符號)指向問題點。
此外,細心的朋友會注意到,在 SyntaxError 異常內容的第一行沒有了之前的(most recent call last )。
這是因為 SyntaxError 是在 Python 嘗試解析代碼時引發的,實際上代碼并沒有執行。
TypeError
當你的代碼試圖對一個無法執行此操作的對象執行某些操作時,例如將字符串添加到整數中,以及一開始的例子使用 append 方法給元組添加元素,這些都會引發 TypeError。
以下是引發 TypeError 的幾個示例:
>>> 1 + '1' Traceback (most recent call last ): File "<stdin>", line 1, in <module> TypeError: unsupported operand type (s ) for +: 'int' and 'str' >>> '1' + 1 Traceback (most recent call last ): File "<stdin>", line 1, in <module> TypeError: must be str, not int >>> len (1) Traceback (most recent call last ): File "<stdin>", line 1, in <module> TypeError: object of type 'int' has no len ()
以上所有引發類型錯誤的示例都會產生包含不同消息的錯誤消息行。它們每一個都能很好地告訴你哪里出了問題。
前兩個示例嘗試將字符串和整數相加。然而,它們有細微的不同
錯誤消息行反映了這些差異。
最后一個示例嘗試在 int 上調用 len ()。
錯誤消息行告訴我們不能使用 int 執行此操作。
ValueError
當對象的值不正確時就會引發 ValueError。這個和我們前面說的因為索引的值不在序列的范圍內,而導致 IndexError 異常類似。
下面看兩個例子
>>> a, b, c = [1, 2] Traceback (most recent call last ): File "<stdin>", line 1, in <module> ValueError: not enough values to unpack (expected 3, got 2) >>> a, b = [1, 2, 3] Traceback (most recent call last ): File "<stdin>", line 1, in <module> ValueError: too many values to unpack (expected 2)
這些示例中的 ValueError 錯誤消息行可以準確地告訴我們值的一些問題:
在第一個示例中,錯誤信息行是沒有足夠多的值去 unpack (解包)。括號理面詳細的寫了你希望解包3個值但實際上只給了2 個。
第二個示例中,錯誤信息行是解包太多的值。先解包3 個值但是只給了2 個變量,所以括號里提示 expected 2 就是說期望的實際是解包2 個值。
上面這些錯誤類型,基本上都是基礎遇到的,希望大家能熟悉記憶。
如何記錄這些錯誤信息呢?
前面我們說了很多異常的相關知識,但是我們應該如何利用好呢,這里我們就重點說一下,如何通過記錄異常信息,方便后期程序的調試。
下面讓我們看一個關于使用 requests 模塊的例子。
首先需要導入 requests 包,使用 pip 即可。
import requests url = "http://wwww.baidu.com" response = requests.get (url ) print (response.status_code, response.text )
這是一個訪問百度的例子,運行之后,我們成功獲取了他的狀態碼和網頁源碼。
接下來我們對 url 進行修改然后再運行。
import requests url = "http://urlis 233.com" response = requests.get (url ) print (response.status_code, response.text )
運行之后我們發現程序出現了錯誤,下面分析下這些錯誤信息
省略前面部分 During handling of the above exception, another exception occurred: Traceback (most recent call last ): File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 3, in <module> response = requests.get (url ) File "/Users/chenxiangan/pythonproject/demo/venv/lib/python 3.7/site-packages/requests/api.py", line 75, in get return request ('get', url, params=params, **kwargs ) File "/Users/chenxiangan/pythonproject/demo/venv/lib/python 3.7/site-packages/requests/api.py", line 60, in request return session.request (method=method, url=url, **kwargs ) File "/Users/chenxiangan/pythonproject/demo/venv/lib/python 3.7/site-packages/requests/sessions.py", line 533, in request resp = self.send (prep, **send_kwargs ) File "/Users/chenxiangan/pythonproject/demo/venv/lib/python 3.7/site-packages/requests/sessions.py", line 646, in send r = adapter.send (request, **kwargs ) File "/Users/chenxiangan/pythonproject/demo/venv/lib/python 3.7/site-packages/requests/adapters.py", line 516, in send raise ConnectionError (e, request=request ) requests.exceptions.ConnectionError: HTTPConnectionPool (host='urlis 233.com', port=80): Max retries exceeded with url: / (Caused by NewConnectionError ('<urllib 3.connection.HTTPConnection object at 0x 10faeba 90>: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))
這個錯誤信息很長,它引發了許多其他的異常,最終的異常類型是 requests.exceptions.ConnectionError。
往前面的錯誤信息找可以發現問題代碼,
File "/Users/chenxiangan/pythonproject/demo/exmpale.py", line 3, in <module> response = requests.get (url )
進而定位到錯誤,這個錯誤原因主要是不存在地址"http://urlis 233.com",所以訪問失敗。
錯誤我們清楚了,但是一大堆的錯誤信息搭載控制臺上,這樣看很不美觀,而且因為異常的原因我們的程序中斷了。這個時候我們就可以使用 Python 中的異常處理模塊 try/except 將代碼改成下面這樣
import requests url = "http://urlis 233.com" try: response = requests.get (url ) except requests.exceptions.ConnectionError: print ("-1","鏈接有問題,訪問失敗") else: print (response.status_code, response.text )
再次運行可以得到下面的結果
-1 鏈接有問題,訪問失敗
ok,我們的程序可以正常運行了,輸出的信息也美觀了。
但是,在大多數實際系統中,我們不希望只是打印捕獲的錯誤信息到控制臺上,而是希望記錄這些信息,方便后面的錯誤排查,所以最好的方案就是通過日志的方式記錄這些程序中的異常。
你可以通過導入 logging 模塊,記錄這些錯誤,最終代碼如下
import logging import requests logger = logging.getLogger (__name__) url = "http://urlis 233.com" try: response = requests.get (url ) except requests.exceptions.ConnectionError as e: logger.exception () print (-1, '鏈接有問題,訪問失敗') else: print (response.status_code, response.content )
現在,當你再運行有問題的 URL 的腳本時,不僅會打印錯誤,同時還會在日志文件中記錄這些錯誤信息。
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
CDA數據分析師證書考試體系(更新于2025年05月22日)
2025-05-26解碼數據基因:從數字敏感度到邏輯思維 每當看到超市貨架上商品的排列變化,你是否會聯想到背后的銷售數據波動?三年前在零售行 ...
2025-05-23在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-25