学习python的日常6

Posted zzy0306

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习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进程再去共享的磁盘上读取文件。

 

以上是关于学习python的日常6的主要内容,如果未能解决你的问题,请参考以下文章

python 机器学习有用的代码片段

学习笔记:python3,代码片段(2017)

python日常练习

日常学习python

学习python的日常4

Python学习总结