當前位置:首頁 » 編程語言 » python列印調用棧

python列印調用棧

發布時間: 2022-05-30 11:24:54

python堆和棧的區別有哪些

堆(Heap)與棧(Stack)是開發人員必須面對的兩個概念,在理解這兩個概念時,需要放到具體的場景下,因為不同場景下,堆與棧代表不同的含義。一般情況下,有兩層含義:
(1)程序內存布局場景下,堆與棧表示的是兩種內存管理方式;
(2)數據結構場景下,堆與棧表示兩種常用的數據結構。
相關推薦:《Python教程》
堆與棧實際上是操作系統對進程佔用的內存空間的兩種管理方式,主要有如下幾種區別:
(1)管理方式不同。棧由操作系統自動分配釋放,無需我們手動控制;堆的申請和釋放工作由程序員控制,容易產生內存泄漏;
(2)空間大小不同。每個進程擁有的棧的大小要遠遠小於堆的大小。理論上,程序員可申請的堆大小為虛擬內存的大小,進程棧的大小 64bits 的 Windows 默認 1MB,64bits 的 Linux 默認 10MB;
(3)生長方向不同。堆的生長方向向上,內存地址由低到高;棧的生長方向向下,內存地址由高到低。
(4)分配方式不同。堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是由操作系統完成的,比如局部變數的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由操作系統進行釋放,無需我們手工實現。
(5)分配效率不同。棧由操作系統自動分配,會在硬體層級對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是由C/C++提供的庫函數或運算符來完成申請與管理,實現機制較為復雜,頻繁的內存申請容易產生內存碎片。顯然,堆的效率比棧要低得多。
(6)存放內容不同。棧存放的內容,函數返回地址、相關參數、局部變數和寄存器內容等。當主函數調用另外一個函數的時候,要對當前函數執行斷點進行保存,需要使用棧來實現,首先入棧的是主函數下一條語句的地址,即擴展指針寄存器的內容(EIP),然後是當前棧幀的底部地址,即擴展基址指針寄存器內容(EBP),再然後是被調函數的實參等,一般情況下是按照從右向左的順序入棧,之後是被調函數的局部變數,注意靜態變數是存放在數據段或者BSS段,是不入棧的。出棧的順序正好相反,最終棧頂指向主函數下一條語句的地址,主程序又從該地址開始執行。堆,一般情況堆頂使用一個位元組的空間來存放堆的大小,而堆中具體存放內容是由程序員來填充的。
從以上可以看到,堆和棧相比,由於大量malloc()/free()或new/delete的使用,容易造成大量的內存碎片,並且可能引發用戶態和核心態的切換,效率較低。棧相比於堆,在程序中應用較為廣泛,最常見的是函數的調用過程由棧來實現,函數返回地址、EBP、實參和局部變數都採用棧的方式存放。雖然棧有眾多的好處,但是由於和堆相比不是那麼靈活,有時候分配大量的內存空間,主要還是用堆。
無論是堆還是棧,在內存使用時都要防止非法越界,越界導致的非法內存訪問可能會摧毀程序的堆、棧數據,輕則導致程序運行處於不確定狀態,獲取不到預期結果,重則導致程序異常崩潰,這些都是我們編程時與內存打交道時應該注意的問題。

❷ python中有沒有像java中的jstack命令

沒有像jstack那麼方便直接用的東西,一般來說有幾個方案:

IDE: 用諸如 PyCharm, Eclpise with Pydev 的工具調試,覺得掛起的時候暫停並檢查各個調用棧。
GDB: 優點是可以調試到native extension,缺點也很明顯,需要在編譯Python的時候加上Debug Symbols,默認這個是沒有的。簡單的說就是功能強大但是配得麻煩。
pdb:適合下斷點...
pudb: 改下代碼,在程序入口import pudb; pudb.set_interrupt_handler(),在運行的時候就可以Ctrl-C進入到互動式調試環境,易用性還好吧。
擼一個singal handler用於列印所有棧信息,參考 celery 實現的 install_cry_handler,或者看看 signalhandler,這個在 Python 3.3 自帶了。

❸ python 捕獲異常時 怎麼調用棧信息

你可以用斷點來看是哪裡出的問題 一般都是這么做的吧 用F9添加斷點到你想要調試的問題 然後用F10調試來查看信息

❹ 用Python 列印函數的定義和調用,求1到任意數字之間能被7整除但不能同時被5整

# -*- coding: utf-8 -*-

def print_num(max):
for i in range(max):
if i % 7 == 0 and i % 5 != 0:
print(i)

print_num(100)

❺ 我執行一段python腳本報錯了,怎麼解決

在程序運行的過程中,如果發生了錯誤,可以事先約定返回一個錯誤代碼,這樣,就可以知道是否有錯,以及出錯的原因。在操作系統提供的調用中,返回錯誤碼非常常見。比如打開文件的函數open(),成功時返迴文件描述符(就是一個整數),出錯時返回-1。
用錯誤碼來表示是否出錯十分不便,因為函數本身應該返回的正常結果和錯誤碼混在一起,造成調用者必須用大量的代碼來判斷是否出錯:

復制代碼代碼如下:

def foo():
r = some_function()
if r==(-1):
return (-1)
# do something
return r

def bar():
r = foo()
if r==(-1):
print 'Error'
else:
pass

一旦出錯,還要一級一級上報,直到某個函數可以處理該錯誤(比如,給用戶輸出一個錯誤信息)。

所以高級語言通常都內置了一套try...except...finally...的錯誤處理機制,Python也不例外。
try
讓我們用一個例子來看看try的機制:

復制代碼代碼如下:

try:
print 'try...'
r = 10 / 0
print 'result:', r
except ZeroDivisionError, e:
print 'except:', e
finally:
print 'finally...'
print 'END'

當我們認為某些代碼可能會出錯時,就可以用try來運行這段代碼,如果執行出錯,則後續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,即except語句塊,執行完except後,如果有finally語句塊,則執行finally語句塊,至此,執行完畢。

上面的代碼在計算10 / 0時會產生一個除法運算錯誤:

復制代碼代碼如下:

try...
except: integer division or molo by zero
finally...
END

從輸出可以看到,當錯誤發生時,後續語句print 'result:', r不會被執行,except由於捕獲到ZeroDivisionError,因此被執行。最後,finally語句被執行。然後,程序繼續按照流程往下走。

如果把除數0改成2,則執行結果如下:

復制代碼代碼如下:

try...
result: 5
finally...
END

由於沒有錯誤發生,所以except語句塊不會被執行,但是finally如果有,則一定會被執行(可以沒有finally語句)。

你還可以猜測,錯誤應該有很多種類,如果發生了不同類型的錯誤,應該由不同的except語句塊處理。沒錯,可以有多個except來捕獲不同類型的錯誤:

復制代碼代碼如下:

try:
print 'try...'
r = 10 / int('a')
print 'result:', r
except ValueError, e:
print 'ValueError:', e
except ZeroDivisionError, e:
print 'ZeroDivisionError:', e
finally:
print 'finally...'
print 'END'

int()函數可能會拋出ValueError,所以我們用一個except捕獲ValueError,用另一個except捕獲ZeroDivisionError。

此外,如果沒有錯誤發生,可以在except語句塊後面加一個else,當沒有錯誤發生時,會自動執行else語句:

復制代碼代碼如下:

try:
print 'try...'
r = 10 / int('a')
print 'result:', r
except ValueError, e:
print 'ValueError:', e
except ZeroDivisionError, e:
print 'ZeroDivisionError:', e
else:
print 'no error!'
finally:
print 'finally...'
print 'END'

Python的錯誤其實也是class,所有的錯誤類型都繼承自BaseException,所以在使用except時需要注意的是,它不但捕獲該類型的錯誤,還把其子類也「一網打盡」。比如:

復制代碼代碼如下:

try:
foo()
except StandardError, e:
print 'StandardError'
except ValueError, e:
print 'ValueError'

第二個except永遠也捕獲不到ValueError,因為ValueError是StandardError的子類,如果有,也被第一個except給捕獲了。

Python所有的錯誤都是從BaseException類派生的
使用try...except捕獲錯誤還有一個巨大的好處,就是可以跨越多層調用,比如函數main()調用foo(),foo()調用bar(),結果bar()出錯了,這時,只要main()捕獲到了,就可以處理:

復制代碼代碼如下:

def foo(s):
return 10 / int(s)

def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except StandardError, e:
print 'Error!'
finally:
print 'finally...'

也就是說,不需要在每個可能出錯的地方去捕獲錯誤,只要在合適的層次去捕獲錯誤就可以了。這樣一來,就大大減少了寫try...except...finally的麻煩。

調用堆棧
如果錯誤沒有被捕獲,它就會一直往上拋,最後被Python解釋器捕獲,列印一個錯誤信息,然後程序退出。來看看err.py:

復制代碼代碼如下:

# err.py:
def foo(s):
return 10 / int(s)

def bar(s):
return foo(s) * 2
def main():
bar('0')
main()

執行,結果如下:

復制代碼代碼如下:

$ python err.py
Traceback (most recent call last):
File "err.py", line 11, in <mole>
main()
File "err.py", line 9, in main
bar('0')
File "err.py", line 6, in bar
return foo(s) * 2
File "err.py", line 3, in foo
return 10 / int(s)
ZeroDivisionError: integer division or molo by zero

出錯並不可怕,可怕的是不知道哪裡出錯了。解讀錯誤信息是定位錯誤的關鍵。我們從上往下可以看到整個錯誤的調用函數鏈:

錯誤信息第1行:

復制代碼代碼如下:

Traceback (most recent call last):

告訴我們這是錯誤的跟蹤信息。

第2行:

復制代碼代碼如下:

File "err.py", line 11, in <mole>
main()

調用main()出錯了,在代碼文件err.py的第11行代碼,但原因是第9行:

復制代碼代碼如下:

File "err.py", line 9, in main
bar('0')

調用bar('0')出錯了,在代碼文件err.py的第9行代碼,但原因是第6行:

復制代碼代碼如下:

File "err.py", line 6, in bar
return foo(s) * 2

原因是return foo(s) * 2這個語句出錯了,但這還不是最終原因,繼續往下看:

復制代碼代碼如下:

File "err.py", line 3, in foo
return 10 / int(s)

原因是return 10 / int(s)這個語句出錯了,這是錯誤產生的源頭,因為下面列印了:

復制代碼代碼如下:

ZeroDivisionError: integer division or molo by zero

根據錯誤類型ZeroDivisionError,我們判斷,int(s)本身並沒有出錯,但是int(s)返回0,在計算10 / 0時出錯,至此,找到錯誤源頭。

記錄錯誤
如果不捕獲錯誤,自然可以讓Python解釋器來列印出錯誤堆棧,但程序也被結束了。既然我們能捕獲錯誤,就可以把錯誤堆棧列印出來,然後分析錯誤原因,同時,讓程序繼續執行下去。
Python內置的logging模塊可以非常容易地記錄錯誤信息:

復制代碼代碼如下:

# err.py
import logging

def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except StandardError, e:
logging.exception(e)
main()
print 'END'

同樣是出錯,但程序列印完錯誤信息後會繼續執行,並正常退出:

復制代碼代碼如下:

$ python err.py
ERROR:root:integer division or molo by zero
Traceback (most recent call last):
File "err.py", line 12, in main
bar('0')
File "err.py", line 8, in bar
return foo(s) * 2
File "err.py", line 5, in foo
return 10 / int(s)
ZeroDivisionError: integer division or molo by zero
END

通過配置,logging還可以把錯誤記錄到日誌文件里,方便事後排查。

拋出錯誤
因為錯誤是class,捕獲一個錯誤就是捕獲到該class的一個實例。因此,錯誤並不是憑空產生的,而是有意創建並拋出的。Python的內置函數會拋出很多類型的錯誤,我們自己編寫的函數也可以拋出錯誤。
如果要拋出錯誤,首先根據需要,可以定義一個錯誤的class,選擇好繼承關系,然後,用raise語句拋出一個錯誤的實例:

復制代碼代碼如下:

# err.py
class FooError(StandardError):
pass

def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n

執行,可以最後跟蹤到我們自己定義的錯誤:

復制代碼代碼如下:

$ python err.py
Traceback (most recent call last):
...
__main__.FooError: invalid value: 0

只有在必要的時候才定義我們自己的錯誤類型。如果可以選擇Python已有的內置的錯誤類型(比如ValueError,TypeError),盡量使用Python內置的錯誤類型。

最後,我們來看另一種錯誤處理的方式:

復制代碼代碼如下:

# err.py
def foo(s):
n = int(s)
return 10 / n

def bar(s):
try:
return foo(s) * 2
except StandardError, e:
print 'Error!'
raise
def main():
bar('0')
main()

在bar()函數中,我們明明已經捕獲了錯誤,但是,列印一個Error!後,又把錯誤通過raise語句拋出去了,這不有病么?

其實這種錯誤處理方式不但沒病,而且相當常見。捕獲錯誤目的只是記錄一下,便於後續追蹤。但是,由於當前函數不知道應該怎麼處理該錯誤,所以,最恰當的方式是繼續往上拋,讓頂層調用者去處理。
raise語句如果不帶參數,就會把當前錯誤原樣拋出。此外,在except中raise一個Error,還可以把一種類型的錯誤轉化成另一種類型:

復制代碼代碼如下:

try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')

只要是合理的轉換邏輯就可以,但是,決不應該把一個IOError轉換成毫不相乾的ValueError。

小結
Python內置的try...except...finally用來處理錯誤十分方便。出錯時,會分析錯誤信息並定位錯誤發生的代碼位置才是最關鍵的。
程序也可以主動拋出錯誤,讓調用者來處理相應的錯誤。但是,應該在文檔中寫清楚可能會拋出哪些錯誤,以及錯誤產生的原因。

❻ python 怎麼列印異常

try:
#你認為會出異常的代碼
exceptException,e:
#異常的堆棧信息
printe
#如果需要拋出異常
raisee

❼ python中怎麼列印行號和文件名

importfileinput
importglob
importstring,sys

forlineinfileinput.input(glob.glob("samples/*.txt")):
iffileinput.isfirstline():#firstinafile?
sys.stderr.write("--reading%s-- "%fileinput.filename())
sys.stdout.write(str(fileinput.lineno())+""+string.upper(line))

用這個

❽ Python記錄詳細調用堆棧日誌的方法

Python記錄詳細調用堆棧日誌的方法
這篇文章主要介紹了Python記錄詳細調用堆棧日誌的方法,涉及Python調用堆棧日誌的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
import sys
import os
def detailtrace(info):
retStr = ""
curindex=0
f = sys._getframe()
f = f.f_back # first frame is detailtrace, ignore it
while hasattr(f, "f_code"):
co = f.f_code
retStr = "%s(%s:%s)->"%(os.path.basename(co.co_filename),
co.co_name,
f.f_lineno) + retStr
f = f.f_back
print retStr+info
def foo():
detailtrace("hello world")
def bar():
foo()
def main():
bar()
if __name__ == "__main__":
main()

輸出:

aaa1.py(<mole>:27)->aaa1.py(main:24)->aaa1.py(bar:21)->aaa1.py(foo:18)->hello world

希望本文所述對大家的Python程序設計有所幫助。

❾ python log exception會列印堆棧么

不會,用import traceback

importtraceback
try:
a=3
b=a+{"1":3}
exceptExceptionase:
print'可以把一下信息寫入日誌'
#如log().info(traceback.print_exc(e))
traceback.print_exc(e)

❿ python實現堆棧與隊列的方法

python實現堆棧與隊列的方法
本文實例講述了python實現堆棧與隊列的方法。分享給大家供大家參考。具體分析如下:
1、python實現堆棧,可先將Stack類寫入文件stack.py,在其它程序文件中使用from stack import Stack,然後就可以使用堆棧了。
stack.py的程序:
代碼如下:class Stack():
def __init__(self,size):
self.size=size;
self.stack=[];
self.top=-1;
def push(self,ele): #入棧之前檢查棧是否已滿
if self.isfull():
raise exception("out of range");
else:
self.stack.append(ele);
self.top=self.top+1;
def pop(self): # 出棧之前檢查棧是否為空
if self.isempty():
raise exception("stack is empty");
else:
self.top=self.top-1;
return self.stack.pop();

def isfull(self):
return self.top+1==self.size;
def isempty(self):
return self.top==-1;
再寫一個程序文件,stacktest.py,使用棧,內容如下:
代碼如下:#!/usr/bin/python
from stack import Stack
s=Stack(20);
for i in range(3):
s.push(i);
s.pop()
print s.isempty();

2、python 實現隊列:
復制代碼代碼如下:class Queue():
def __init__(self,size):
self.size=size;
self.front=-1;
self.rear=-1;
self.queue=[];
def enqueue(self,ele): #入隊操作
if self.isfull():
raise exception("queue is full");
else:
self.queue.append(ele);
self.rear=self.rear+1;
def dequeue(self): #出隊操作
if self.isempty():
raise exception("queue is empty");
else:
self.front=self.front+1;
return self.queue[self.front];
def isfull(self):
return self.rear-self.front+1==self.size;
def isempty(self):
return self.front==self.rear;

q=Queue(10);
for i in range(3):
q.enqueue(i);
print q.dequeue();
print q.isempty();
希望本文所述對大家的Python程序設計有所幫助。

熱點內容
javawsdl2java 發布:2025-02-12 02:25:21 瀏覽:366
java默認許可權 發布:2025-02-12 02:25:20 瀏覽:655
演算法預測用戶 發布:2025-02-12 02:24:44 瀏覽:390
舊電腦搭建網路列印伺服器 發布:2025-02-12 02:09:45 瀏覽:648
c語言順序表基本操作 發布:2025-02-12 02:09:41 瀏覽:887
安卓光遇怎麼開三檔畫質華為 發布:2025-02-12 01:55:51 瀏覽:193
微信哪裡能找到登陸游戲的密碼 發布:2025-02-12 01:54:22 瀏覽:591
php獲取伺服器ip地址 發布:2025-02-12 01:54:12 瀏覽:578
對象存儲和nas哪個好 發布:2025-02-12 01:50:34 瀏覽:445
phpmulticurl 發布:2025-02-12 01:41:58 瀏覽:70