调试和分析Python脚本

  • 来源 | 愿码(ChainDesk.CN)内容编辑
  • 愿码Slogan | 链接每一个程序员的故事
  • 网站 | http://chaindesk.cn
  • 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优点创造睡后收入。
  • 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
  • 免费加入愿码全思惟工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码

本文阅读时长:11minpython

调试和分析在Python开发中发挥重要做用 。调试器可帮助程序员分析完整的代码。调试器设置断点,而分析器运行咱们的代码并向咱们提供执行时间的详细信息,分析器将识别程序中的瓶颈。linux

Python调试技术


调试是一个解决代码中出现的问题并阻止软件正常运行的过程。在Python中,调试很是简单。Python调试器设置条件断点并一次调试一行源代码。咱们将使用pdb Python标准库中的模块调试咱们的Python脚本 。程序员

为了更好地调试Python程序,可使用各类技术。咱们将讨论Python调试的四种技术:ubuntu

  • print() 声明:这是了解发生了什么的最简单方法,所以您能够检查已执行的内容。
  • logging:这就像一个print声明,但有更多的上下文信息,因此你能够彻底理解它。
  • pdb debugger:这是一种经常使用的调试技术。使用的优势pdb是您能够pdb从命令行,解释器和程序中使用。
  • IDE调试器:IDE具备集成调试器。它容许开发人员执行他们的代码,而后开发人员能够在程序执行时进行检查。

错误处理(异常处理)


在本节中,咱们将学习Python如何处理异常。例外是程序执行期间发生的错误。每当发生任何错误时,Python都会生成一个异常,该异常将使用try ... except块进行处理。程序没法处理某些异常,所以会致使错误消息。如今,咱们将看到一些异常示例。app

在终端中,启动 python3交互式控制台,咱们将看到一些异常示例:函数

student@ubuntu:~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> 50 / 0

Traceback (most recent call last):
 File "", line 1, in ZeroDivisionError: division by zero
>>>
>>> 6 + abc*5
Traceback (most recent call last):
  File "", line 1, in NameError: name 'abc' is not defined
>>>
>>> 'abc' + 2
Traceback (most recent call last):
  File "", line 1, in TypeError: Can't convert 'int' object to str implicitly
>>>
>>> import abcd
Traceback (most recent call last):
  File "", line 1, in ImportError: No module named 'abcd'
>>>

这些是例外的一些例子。如今,咱们将看到咱们如何处理异常。工具

每当Python程序中发生错误时,都会引起异常。咱们还可使用raise关键字强制引起异常。学习

如今咱们将看到一个try…except处理异常的块。在try块中,咱们将编写可能生成异常的代码。在except块中,咱们将为该异常编写解决方案。区块链

语法 try…except以下:测试

try:
            statement(s)
except:
            statement(s)

一个try块能够有多个except语句。咱们也能够经过在except关键字后面输入例外名称来处理特定的例外。处理特定异常的语法以下:

try:
            statement(s)
except exception_name:
            statement(s)

咱们将建立一个exception_example.py 要捕获的脚本ZeroDivisionError在脚本中编写如下代码:

a = 35
b = 57
try:
            c = a + b
            print("The value of c is: ", c)
            d = b / 0
            print("The value of d is: ", d)
 
except:
            print("Division by zero is not possible")
 
print("Out of try...except block")

按以下所示运行脚本,您将得到如下输出:

student@ubuntu:~$ python3 exception_example.py
The value of c is:  92
Division by zero is not possible
Out of try...except block

调试器工具


Python支持许多调试工具:

  • winpdb
  • pydev
  • pydb
  • pdb
  • gdb
  • pyDebug

在本节中,咱们将学习pdb Python调试器。pdbmodule是Python标准库的一部分,始终可供使用。

pdb调试器

该pdb模块用于调试Python程序。Python程序使用pdb交互式源代码调试器来调试程序。pdb设置断点并检查堆栈帧,并列出源代码。

如今咱们将了解如何使用pdb调试器。有三种方法可使用此调试器:

· 在解释器中

· 从命令行

· 在Python脚本中

咱们将建立一个pdb_example.py脚本并在该脚本中添加如下内容:

class Student:
            def __init__(self, std):
                        self.count = std
 
            def print_std(self):
                        for i in range(self.count):
                                    print(i)
                        return
if __name__ == '__main__':
            Student(5).print_std()

以此脚本为例学习Python调试,咱们将看到如何详细启动调试器。

在解释器中


要从Python交互式控制台启动调试器,咱们使用run()或runeval()。

启动python3交互式控制台。运行如下命令以启动控制台:

$ python3

导入咱们的 pdb_example脚本名称和pdb模块。如今,咱们将使用run()而且咱们将字符串表达式做为参数传递给run()Python解释器自己:

student@ubuntu:~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import pdb_example
>>> import pdb
>>> pdb.run('pdb_example.Student(5).print_std()')
> (1)()
(Pdb)

要继续调试,请continue在(Pdb)提示符后输入并按Enter键。若是你想知道咱们能够在这里使用的选项,那么在(Pdb)提示后按两次Tab 键。

如今,输入后continue,咱们将得到以下输出:

student@ubuntu:~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import pdb_example
>>> import pdb
>>> pdb.run('pdb_example.Student(5).print_std()')
> (1)()
(Pdb) continue
0
1
2
3
4
>>>

从命令行


运行调试器的最简单,最直接的方法是从命令行。咱们的程序将做为调试器的输入。您能够从命令行使用调试器,以下所示:

$ python3 -m pdb pdb_example.py

从命令行运行调试器时,将加载源代码,它将中止在找到的第一行执行。输入continue以继续调试。这是输出:

student@ubuntu:~$ python3 -m pdb pdb_example.py
> /home/student/pdb_example.py(1)()
-> class Student:
(Pdb) continue
0
1
2
3
4
The program finished and will be restarted
> /home/student/pdb_example.py(1)()
-> class Student:
(Pdb)

在Python脚本中


前两种技术将在Python程序开始时启动调试器。但这第三种技术最适合长期运行的流程。要在脚本中启动调试器,请使用set_trace()。

如今,修改您的pdb_example.py 文件,以下所示:

import pdb
class Student:
            def __init__(self, std):
                        self.count = std
 
            def print_std(self):
                        for i in range(self.count):
                                    pdb.set_trace()
                                    print(i)
                        return
 
if __name__ == '__main__':
            Student(5).print_std()

如今,按以下方式运行程序:

student@ubuntu:~$ python3 pdb_example.py
> /home/student/pdb_example.py(10)print_std()
-> print(i)
(Pdb) continue
0
> /home/student/pdb_example.py(9)print_std()
-> pdb.set_trace()
(Pdb)

set_trace() 是一个Python函数,所以您能够在程序中的任何位置调用它。

所以,这些是启动调试器的三种方式。

调试基本程序崩溃


在本节中,咱们将看到跟踪模块。跟踪模块有助于跟踪程序执行。所以,每当您的Python程序崩溃时,咱们均可以理解崩溃的位置。咱们能够经过将跟踪模块导入您的脚本以及命令行来使用它。

如今,咱们将建立一个名为脚本trace_example.py并在脚本中编写如下内容:

class Student:
            def __init__(self, std):
                        self.count = std
 
            def go(self):
                        for i in range(self.count):
                                    print(i)
                        return
if __name__ == '__main__':
            Student(5).go()

输出以下:

student@ubuntu:~$ python3 -m trace --trace trace_example.py
 --- modulename: trace_example, funcname: trace_example.py(1): class Student:
 --- modulename: trace_example, funcname: Student
trace_example.py(1): class Student:
trace_example.py(2):   def __init__(self, std):
trace_example.py(5):   def go(self):
trace_example.py(10): if __name__ == '__main__':
trace_example.py(11):             Student(5).go()
 --- modulename: trace_example, funcname: init
trace_example.py(3):               self.count = std
 --- modulename: trace_example, funcname: go
trace_example.py(6):               for i in range(self.count):
trace_example.py(7):                           print(i)
0
trace_example.py(6):               for i in range(self.count):
trace_example.py(7):                           print(i)
1
trace_example.py(6):               for i in range(self.count):
trace_example.py(7):                           print(i)
2
trace_example.py(6):               for i in range(self.count):
trace_example.py(7):                           print(i)
3
trace_example.py(6):               for i in range(self.count):
trace_example.py(7):                           print(i)
4

所以,经过trace --trace在命令行使用,开发人员能够逐行跟踪程序。所以,只要程序崩溃,开发人员就会知道崩溃的实例。

分析和计时程序


分析Python程序意味着测量程序的执行时间。它衡量每一个功能所花费的时间。Python的cProfile模块用于分析Python程序。

cProfile模块

如前所述,分析意味着测量程序的执行时间。咱们将使用cProfile Python模块来分析程序。

如今,咱们将编写一个 cprof_example.py 脚本并在其中编写如下代码:

mul_value = 0
def mul_numbers( num1, num2 ):
            mul_value = num1 * num2;
            print ("Local Value: ", mul_value)
            return mul_value
mul_numbers( 58, 77 )
print ("Global Value: ", mul_value)

运行程序,您将看到以下输出:

student@ubuntu:~$ python3 -m cProfile cprof_example.py
Local Value:  4466
Global Value:  0
         6 function calls in 0.000 seconds
   Ordered by: standard name
 
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 cprof_example.py:1()
        1    0.000    0.000    0.000    0.000 cprof_example.py:2(mul_numbers)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        2    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

所以,使用时cProfile,全部被调用的函数都将打印出每一个函数所花费的时间。如今,咱们将看到这些列标题的含义:

· ncalls: 通话次数

· tottime: 在给定函数中花费的总时间

· percall:商数tottime除以ncalls

· cumtime:在此和全部方面花费的累计时间 subfunctions

· percall:cumtime除以原始调用的商数

· filename:lineno(function):提供每一个功能的相应数据

timeit

timeit是一个Python模块,用于计算Python脚本的一小部分。您能够从命令行调用timeit,也能够将timeit模块导入到脚本中。咱们将编写一个脚原本计算一段代码。建立一个timeit_example.py脚本并将如下内容写入其中:

import timeit
prg_setup = "from math import sqrt"
prg_code = '''
def timeit_example():
            list1 = []
            for x in range(50):
                        list1.append(sqrt(x))
'''
# timeit statement
print(timeit.timeit(setup = prg_setup, stmt = prg_code, number = 10000))

使用timeit,咱们能够决定咱们要测量的代码片断。所以,咱们能够轻松定义设置代码以及咱们要单独执行测试的代码段。主代码运行100万次,这是默认时间,而设置代码只运行一次。

使程序运行得更快


有多种方法可使Python程序运行得更快,例如:

  • 描述您的代码,以便识别瓶颈
  • 使用内置函数和库,所以解释器不须要执行循环
  • 避免使用全局变量,由于Python在访问全局变量时很是慢
  • 使用现有包
相关文章
相关标签/搜索