学习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的主要内容,如果未能解决你的问题,请参考以下文章