Python 中的 pdb 模組

來源:互聯網
上載者:User

標籤:python pdb

PYTHON 代碼,尤其是別人寫的代碼看不懂。怎麼辦? 其實PYTHON中也提供了類似於C語言中用於debug 的 gdb。它叫做pdb。結合本人自己的學習,進行簡單的舉例,以做備忘和補償學習。


首先參考資料:

1、http://web.stanford.edu/class/physics91si/2013/handouts/Pdb_Commands.pdf

2、https://docs.python.org/2/library/pdb.html


以 shadowsocks 的 local.py 代碼為例子,示範相應的基本命令使用。


local.py 代碼:

#!/usr/bin/env python# -*- coding: utf-8 -*-## Copyright 2012-2015 clowwindy## Licensed under the Apache License, Version 2.0 (the "License"); you may# not use this file except in compliance with the License. You may obtain# a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the# License for the specific language governing permissions and limitations# under the License.from __future__ import absolute_import, division, print_function,     with_statementimport sysimport osimport loggingimport signalsys.path.insert(0, os.path.join(os.path.dirname(__file__), ‘../‘))from shadowsocks import shell, daemon, eventloop, tcprelay, udprelay, asyncdnsdef main():    shell.check_python()    # fix py2exe    if hasattr(sys, "frozen") and sys.frozen in             ("windows_exe", "console_exe"):        p = os.path.dirname(os.path.abspath(sys.executable))        os.chdir(p)    config = shell.get_config(True)    daemon.daemon_exec(config)    try:        logging.info("starting local at %s:%d" %                     (config[‘local_address‘], config[‘local_port‘]))        dns_resolver = asyncdns.DNSResolver()        tcp_server = tcprelay.TCPRelay(config, dns_resolver, True)        udp_server = udprelay.UDPRelay(config, dns_resolver, True)        loop = eventloop.EventLoop()        dns_resolver.add_to_loop(loop)        tcp_server.add_to_loop(loop)        udp_server.add_to_loop(loop)        def handler(signum, _):            logging.warn(‘received SIGQUIT, doing graceful shutting down..‘)            tcp_server.close(next_tick=True)            udp_server.close(next_tick=True)        signal.signal(getattr(signal, ‘SIGQUIT‘, signal.SIGTERM), handler)        def int_handler(signum, _):            sys.exit(1)        signal.signal(signal.SIGINT, int_handler)        daemon.set_user(config.get(‘user‘, None))        loop.run()    except Exception as e:        shell.print_exception(e)        sys.exit(1)if __name__ == ‘__main__‘:    main()


為了配合測試,寫了一個假的設定檔config.json:

{    "server":"127.0j.0.1",    "server_port":8388,    "local_port":10808,    "password":"bgt56yhn",    "timeout":600,    "method":null}


一、如何使用pdb 進行調試和擷取協助

1、指令碼啟動時,即載入pdb 調試資訊

python -m pdb scriptfile [arg] #此中情況,程式在代碼的第一行設定了一個斷點


2、變更指令碼加入pdb 調試資訊

import pdbpdb.set_trace()   # 在程式某處設定斷點


OK ,我們這裡為了圖簡單,就不去更改local.py 原始碼了,直接使用第一種方法去調試

 $ python -m pdb local.py  -c config.json> /home/test/python/shadowsocks/shadowsocks/local.py(18)<module>()-> from __future__ import absolute_import, division, print_function, (Pdb) helpDocumented commands (type help <topic>):========================================EOF    bt         cont      enable  jump  pp       run      unt   a      c          continue  exit    l     q        s        until alias  cl         d         h       list  quit     step     up    args   clear      debug     help    n     r        tbreak   w     b      commands   disable   ignore  next  restart  u        whatisbreak  condition  down      j       p     return   unalias  where Miscellaneous help topics:==========================exec  pdbUndocumented commands:======================retval  rv

從以上結果也可以看出,預設代碼的第一行為斷點(只是一個假象的斷點,顯示斷點指令是看不到的),程式停留在此處。

在pdb 狀態下,使用help 指令可以擷取pdb的協助資訊。


二、n(next)

n(next) 輸入的時候,可以執行代碼的下一行。

(Pdb) n> /home/test/python/shadowsocks/shadowsocks/local.py(21)<module>()-> import sys(Pdb) n> /home/test/python/shadowsocks/shadowsocks/local.py(22)<module>()-> import os(Pdb) n> /home/test/python/shadowsocks/shadowsocks/local.py(23)<module>()-> import logging(Pdb)           # 此處為空白,按了一個斷行符號鍵> /home/test/python/shadowsocks/shadowsocks/local.py(24)<module>()-> import signal(Pdb)          # 此處為空白,按了一個斷行符號鍵> /home/test/python/shadowsocks/shadowsocks/local.py(26)<module>()-> sys.path.insert(0, os.path.join(os.path.dirname(__file__), ‘../‘))(Pdb)

注意:
一個很牛的特性是你可以單擊斷行符號鍵來執行以前的命令(在上面的例子中執行的指令為n)。


三、s(step) 、  b(break) 和 c(continue) 指令

s(step) 輸入的時候,可以進入這行代碼中的相關函數去執行

b num 輸入的時候,是在某行(num)上設定一個斷點。若直接輸入b ,則顯示所有的斷點

本來,打算講s(step)指令和 n(next)指令放到一起,做個比較。不過我更感覺s(step) 指令應該和b(break) 及 c(continue)結合起來一起用,這樣感覺效率上更高。

以實際操作去說話,我想在main()函數上打一個斷點,然後直接走到這個斷點,最後進入main函數。

前提,我知道了 main() 函數位於 72行(函數位於檔案中的哪一行,這個靠自己了)

> /home/test/python/shadowsocks/shadowsocks/local.py(18)<module>()-> from __future__ import absolute_import, division, print_function, (Pdb) b 72     # 在72 行設定一個斷點Breakpoint 1 at /home/test/python/shadowsocks/shadowsocks/local.py:72(Pdb) b        # 顯示所有的斷點Num Type         Disp Enb   Where1   breakpoint   keep yes   at /home/test/python/shadowsocks/shadowsocks/local.py:72(Pdb) c        # 直接走到這個斷點處> /home/test/python/shadowsocks/shadowsocks/local.py(72)<module>()-> main()(Pdb) s        # s ,進入main 函數--Call--> /home/dexin/python/shadowsocks/shadowsocks/local.py(30)main()-> def main():(Pdb) l 25       26      sys.path.insert(0, os.path.join(os.path.dirname(__file__), ‘../‘)) 27      from shadowsocks import shell, daemon, eventloop, tcprelay, udprelay, asyncdns 28       29       30  ->    def main(): 31          shell.check_python() 32       33          # fix py2exe 34          if hasattr(sys, "frozen") and sys.frozen in  35                  ("windows_exe", "console_exe"):(Pdb) n         # n 移動到下一行> /home/dexin/python/shadowsocks/shadowsocks/local.py(31)main()-> shell.check_python()(Pdb) s         # s 進入到 check_python 函數--Call--> /home/dexin/python/shadowsocks/shadowsocks/shell.py(35)check_python()-> def check_python():(Pdb)

以上調試中,用的了 l(list) 指令,這個指令的意思為顯示代碼。預設什麼參數也沒有的情況下。

顯示當前行上下共11行代碼。


四、clear num 清除先前設定的斷點 ,這裡的num 為第幾個斷點的意思

(Pdb) b 34Breakpoint 1 at /home/test/python/shadowsocks/shadowsocks/local.py:34(Pdb) bNum Type         Disp Enb   Where1   breakpoint   keep yes   at /home/test/python/shadowsocks/shadowsocks/local.py:34(Pdb) l 36              p = os.path.dirname(os.path.abspath(sys.executable)) 37              os.chdir(p) 38       39          config = shell.get_config(True) 40       41          daemon.daemon_exec(config) 42       43          try: 44              logging.info("starting local at %s:%d" % 45                           (config[‘local_address‘], config[‘local_port‘])) 46      (Pdb) b 41Breakpoint 2 at /home/dexin/python/shadowsocks/shadowsocks/local.py:41(Pdb) b         # 顯示所有的斷點Num Type         Disp Enb   Where1   breakpoint   keep yes   at /home/dexin/python/shadowsocks/shadowsocks/local.py:342   breakpoint   keep yes   at /home/dexin/python/shadowsocks/shadowsocks/local.py:41(Pdb) clear 1    # 清除第一個斷點Deleted breakpoint 1(Pdb) bNum Type         Disp Enb   Where2   breakpoint   keep yes   at /home/dexin/python/shadowsocks/shadowsocks/local.py:41(Pdb)


五、p(print) 列印

這個指令的功能主要用於列印程式中的變數值

(Pdb) n> /home/test/python/shadowsocks/shadowsocks/shell.py(37)check_python()-> if info[0] == 2 and not info[1] >= 6:(Pdb) l 32      verbose = 0 33       34       35      def check_python(): 36          info = sys.version_info 37  ->        if info[0] == 2 and not info[1] >= 6: 38              print(‘Python 2.6+ required‘) 39              sys.exit(1) 40          elif info[0] == 3 and not info[1] >= 3: 41              print(‘Python 3.3+ required‘) 42              sys.exit(1)(Pdb) p info  # 列印變數值sys.version_info(major=2, minor=7, micro=6, releaselevel=‘final‘, serial=0)


六、動態調整變數的值

(Pdb) n> /home/test/python/shadowsocks/shadowsocks/shell.py(37)check_python()-> if info[0] == 2 and not info[1] >= 6:(Pdb) l 32      verbose = 0 33       34       35      def check_python(): 36          info = sys.version_info 37  ->        if info[0] == 2 and not info[1] >= 6: 38              print(‘Python 2.6+ required‘) 39              sys.exit(1) 40          elif info[0] == 3 and not info[1] >= 3: 41              print(‘Python 3.3+ required‘) 42              sys.exit(1)(Pdb) p infosys.version_info(major=2, minor=7, micro=6, releaselevel=‘final‘, serial=0)(Pdb) info = (11,22,33)(Pdb) p info(11, 22, 33)


七、q(quit)退出

(Pdb) quit

本文出自 “學習筆記” 部落格,請務必保留此出處http://unixman.blog.51cto.com/10163040/1663867

Python 中的 pdb 模組

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.