美文网首页
调试和分析Python脚本

调试和分析Python脚本

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

    本文阅读时长:11min

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

    Python调试技术


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

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

    • print() 声明:这是了解发生了什么的最简单方法,因此您可以检查已执行的内容。

    • logging:这就像一个print声明,但有更多的上下文信息,所以你可以完全理解它。

    • pdb debugger:这是一种常用的调试技术。使用的优点pdb是您可以pdb从命令行,解释器和程序中使用。

    • IDE调试器:IDE具有集成调试器。它允许开发人员执行他们的代码,然后开发人员可以在程序执行时进行检查。

    错误处理(异常处理)


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

    在终端中,启动 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在访问全局变量时非常慢

    • 使用现有包

    相关文章

      网友评论

          本文标题:调试和分析Python脚本

          本文链接:https://www.haomeiwen.com/subject/zndiiqtx.html