zoukankan      html  css  js  c++  java
  • 学习python的日常6

    错误、调试和测试:

    错误处理:

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

     首先是执行语句,然后发现错误了就会跳转到执行except,语句,然后按顺序执行,如果是正确的就不会执行except语句。

    其中的Error还可以细分,错误本身也是一个类,都继承自BaseException,所以尽量不要出现错误的父类和子类同时捕获,

    因为这时候只会执行父类的捕获错误。

    调用栈:

    如果一个错误没有被捕获,就会一直往上抛,最后被python解释器捕获,出错的时候通过分析错误的调用栈信息,可以定位

    错误的位置。

    记录错误:

    python内置的logging模块可以非常容易地记录错误信息

    # err_logging.py
    
    import logging
    
    def foo(s):
        return 10 / int(s)
    
    def bar(s):
        return foo(s) * 2
    
    def main():
        try:
            bar('0')
        except Exception as e:
            logging.exception(e)
    
    main()
    print('END')
    
    $ python3 err_logging.py
    ERROR:root:division by zero
    Traceback (most recent call last):
      File "err_logging.py", line 13, in main
        bar('0')
      File "err_logging.py", line 9, in bar
        return foo(s) * 2
      File "err_logging.py", line 6, in foo
        return 10 / int(s)
    ZeroDivisionError: division by zero
    END
    

    抛出错误:

    因为错误是class,然后捕获一个错误就是捕获到一个实例,如果要抛出错误,可以根据需要定义一个错误的class,

    选择好继承关系,然后用raise语句抛出一个错误的实例。只有在必要的时候才定义我们自己的错误类型,如果可以,

    尽量使用python内置的错误类型。

    最后还有一种错误处理的方式:

    # err_reraise.py
    
    def foo(s): 
        n = int(s)
        if n==0:
            raise ValueError('invalid value: %s' % s)
        return 10 / n
    
    def bar():
        try:
            foo('0')
        except ValueError as e:
            print('ValueError!')
            raise
    
    bar()
    

     捕获异常后,又把错误用过raise语句抛出去,是因为,捕获错误的目的只是记录一下,由于当前函数不知道

    应该怎么处理该错误,所以往上抛是一种很好的方式,最终会让顶层调用者去处理。

    调试:

    1.一种方法简单粗暴,直接用print()打印。

    2.断言,凡是用print()来辅助查看的都可以用断言(assert)来替代。

    3.logging,把print()替换为logging是第三种方式,logging可以指定记录信息的级别,有debug,info,warning,error

    等几个级别,指定高级别的时候,低级别就不起作用了。

    4.pdb,启用python的调试器pdb,让程序以单步方式运行,可以随时查看运行状态。pdb.set_trace(),也是用pdb,只

    需要导入pdb,然后在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点,到了之后就会暂停并进入pdb

    调试环境,用p可以查看变量,用c继续运行。

    5.IDE,支持调试功能的IDE,有一些比较好的Python IDE。

    单元测试:

    用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。我们给出一系列数据,然后期望输出的结果是我们

    预期的结果,如果不相符就说明我们的代码中存在问题。

    文档测试:

    利用注释来告知代码我们希望得到的结果,然后又一些工具来自动生成文档。

    IO编程:

    IO指的是Input/Output,也就是输入和输出。IO编程中由于内外设备的速度不匹配,又可以分为同步IO和异步IO两种方式,

    现在涉及到的是同步IO

    文件读写:

    读文件

    >>> f = open('/Users/michael/test.txt', 'r')
    

     如果不存在就会报错,然后如果成功打开调用read()方法就可以一次性读到内存当中,用一个str对象表示,要记得调用

    close()方法来关闭文件,如果出错是无法关闭文件的,f.close()也不会调用,所以用try...finally来实现,但是总写会很麻烦,

    所以可以调用python的with语句来自动调用close()方法:

    with open('/path/to/file', 'r') as f:
        print(f.read())
    

      想open()函数这种返回有个read()方法的对象,在python中统称为file-like Object,除了file外还有很多其他的流,不过只要

    有个read()方法就可以了。读

    >>> from io import StringIO
    >>> f = StringIO()
    >>> f.write('hello')
    5
    >>> f.write(' ')
    1
    >>> f.write('world!')
    6
    >>> print(f.getvalue())
    hello world!
    

      操作二进制数据就需要使用BytesIO。

    StringIO和BytesIO是在内存中操作str和bytes的方法,使得和读写文件具有一致的接口。

    取二进制文件,用’rb‘模式打开文件就行;读取字符编码文本文件,添加一个encoding=’gkb',遇到

    不规范的可以添加参数errors=‘ignore'。

    写文件

    >>> f = open('/Users/michael/test.txt', 'w')
    >>> f.write('Hello, world!')
    >>> f.close()
    

     写文件和读文件一样,不过区别在于传入的标识符,‘w'或者’wb‘表示文本文件或者写二进制文件,如果要写入特定编码的文本

    文件,要给open()传入encoding参数,将字符串自动转换成特定编码。

    StringIO和BytesIO

    操作文件和目录:

    python的os模块封装了操作系统的目录和文件操作,这些函数有的在os模块中,有的在os.path模块中。

    序列化:

    把变量从内存中变成可存储或可传输的过程称之为序列化,反过来把变量内容从序列化的对象重新读到内存里称之为反序列化。

    python提供pickle模块来实现序列化,但是要把序列变得更通用、更符合Web标准,就可以使用json模块。

    json模块的dumps()和loads()函数是用来序列化和反序列化的,如果默认的序列化和反序列化机制不满足要求时,可以传入更多

    的参数来定制序列化或反序列化规则。

    进程和线程:

    多任务的实现方式有3种:1.多进程模式;

                                               2.多线程模式;

                                               3.多进程+多线程模式

    线程时最小的执行单元,而进程由至少一个线程组成。

    多进程:

    在Unix/Linux下,可以使用fork()调用实现多进程。

    如果要实现跨平台的多进程,可以使用multiprocessing模块。

    subprocess模块可以很方便地启动一个子进程,然后控制其输入和输出。

    进程间通信时通过Queue、Pipes等实现地。

    多线程:

    同一个进程内多个线程,python地标准库提供了_thread和threading两个模块,绝大多数下使用threading这个高级模块。

    启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。多线程中,由于线程地调度是由系统

    决定地,当线程交替执行时,很容易造成内容被乱改。为了确保变量,可以给线程上锁,一个进程提供一个锁,然后让

    线程去获取该锁,这样线程就只有在获得锁的情况下才能执行语句,就不会造成冲突了。然后坏处的话只要时降低了

    效率以及容易造成死锁。Python的解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,

    必须先获得GIL锁。这个GIL全局锁实际上把所有线程的执行代码都给上锁。

    ThreadLocal:

    import threading
    
    # 创建全局ThreadLocal对象:
    local_school = threading.local()
    
    def process_student():
        # 获取当前线程关联的student:
        std = local_school.student
        print('Hello, %s (in %s)' % (std, threading.current_thread().name))
    
    def process_thread(name):
        # 绑定ThreadLocal的student:
        local_school.student = name
        process_student()
    
    t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
    t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    

      

    局部变量在函数调用时很麻烦,一层一层传递很麻烦,全局变量local_school就是一个ThreadLocal对象,每个Thread

    对它都可以读写student属性,但互不影响。可以把local_school看成全局变量,每个属性如local_school.student都是线

    程的局部变量,可以任意读写而互不干扰,也不用管理锁的问题,ThreadLocal内部会处理。

    ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调

    用到的处理函数都可以非常方便地访问这些资源。一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己

    线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数都可以非常方便地访问这些资源。

    分布式进程:

    Python地分布式进程接口简单,封装良好,适合需要把繁重任务分布到多台机器地环境下。

    注意Queue地作用是用来传递任务和接收结果,每个任务的描述数据量要尽量小。比如发送一个处理日志文件的任务,

    就不要发送几百兆的日志文件本身,而是发送日志文件存放的完整路径,由Worker进程再去共享的磁盘上读取文件。

  • 相关阅读:
    0-1性能测试需求分析
    1-10jmeter关联,正则表达式(待巩固)
    1-9jmeter集合点,并发操作
    1-8.jmeter设置断言(检查点)
    1-6jmeter性能测试基础
    泛型中的协变和逆变
    jsPlumb
    jQuery UI vs Kendo UI & jQuery Mobile vs Kendo UI Mobile
    31天重构
    Visual Studio 小工具
  • 原文地址:https://www.cnblogs.com/zzy0306/p/7979049.html
Copyright © 2011-2022 走看看