错误、调试、测试、IO编程、进线和线程

#错误、调试和测试
##错误

try:
    foo()
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')

第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类,已经被第一个except捕获。所有的错误类型都基于BasEexception。

Traceback (most recent call last):#错误跟踪信息
  File "err.py", line 11, in <module>
    main()#main()出错,对应第11行,原因却在第9行
  File "err.py", line 9, in main
    bar('0')
  File "err.py", line 6, in bar
    return foo(s) * 2
  File "err.py", line 3, in foo
    return 10 / int(s)
ZeroDivisionError: division by zero

这个是调用栈,如果错误没找到,则一直向上传递。
用logging函数记录错误信息。
用raise函数抛出错误。

Traceback (most recent call last):
  File "err_throw.py", line 11, in <module>
    foo('0')
  File "err_throw.py", line 8, in foo
    raise FooError('invalid value: %s' % s)#raise函数展示了我们自己定义的错误类型
__main__.FooError: invalid value: 0#raise抛出了我们自己定义的错误类型

##调试
在找bug时需要打印错误信息,用assert,最后调用-O即可。

def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n

def main():
    foo('0')

但是升级版的logging更好,它可以把错误传向文件。

import logging
logging.basicConfig(level=logging.INFO)

加上第二行语句就可以把错误传向文件十分方便。可以迅速找到文件错误的位置。

##单元测试
单元测试就是对某一类进行测试,如果将来把这个类修改了,只需要调用单元测试来判断这个类有没有错误。

import unittest

from mydict import Dict

class TestDict(unittest.TestCase):

    def test_init(self):
        d = Dict(a=1, b='test')
        self.assertEqual(d.a, 1)#断言输出是不是我们所期望的
        self.assertEqual(d.b, 'test')
        self.assertTrue(isinstance(d, dict))

引入python自带的unittest进行测试,用assertEqual断言,还可以返回出错误类型等等我们所期望的。

if __name__ == '__main__':
    unittest.main()

调用最后两行代码执行单元测试。
#IO编程
##StringIO和BytesIO
二进制写入文件

>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))#写入的不是字符串
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'

读取二进制的文件

>>> from io import BytesIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87

##操作文件和目录
posix对应windows系统

>>> os.environ.get('PATH')
'/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin'

获取某个环境变量的值

# 查看当前目录的绝对路径:
>>> os.path.abspath('.')
'/Users/michael'
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 然后创建一个目录:
>>> os.mkdir('/Users/michael/testdir')
# 删掉一个目录:
>>> os.rmdir('/Users/michael/testdir')
#合并路径:
os.path.join()
#拆分路径:
os.path.split()
#直接得到文件扩展名:
os.path.splitext()
#列出当前目录下所有目录:
>>> [x for x in os.listdir('.') if os.path.isdir(x)]
['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Applications', 'Desktop', ...]
#列出所有py文件:
>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']

##序列化
我们把变量从内存中变成可存储或传输的过程称之为序列化,pickling,反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
具体操作如下:

>>> import pickle
>>> d = dict(name='Bob', age=20, score=88)
>>> pickle.dumps(d)#用这个函数把它序列化
b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x14X\x05\x00\x00\x00scoreq\x02KXX\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Bobq\x04u.'
>>> f = open('dump.txt', 'wb')
>>> pickle.dump(d, f)#用这个函数把对象序列化后写入file-like Object
>>> f.close()
>>> f = open('dump.txt', 'rb')
>>> d = pickle.load(f)#用这个函数把序列化的内容转回来
>>> f.close()
>>> d
{'age': 20, 'score': 88, 'name': 'Bob'}

#进程和线程
##多进程multiprocessing
创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

如果创建大量的子进程,需要用进程池的方法。

import subprocess

print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])#在python代码中运行这个命令
print('Exit code:', r)

进程间通信是通过Queue、Pipes等实现的。
##多线程
多任务可以由多进程完成,也可以由一个进程内的多线程完成。
一个简单的运算balance = balance + n在CPU中也可以分成两步,因此经常会出错。

balance = 0
lock = threading.Lock()

def run_thread(n):
    for i in range(100000):
        # 先要获取锁:
        lock.acquire()
        try:
            # 放心地改吧:
            change_it(n)
        finally:
            # 改完了一定要释放锁:
            lock.release()

用threading.Lock()可以有效解决这个问题。
分布式进程:把任务发送到多台计算机上执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值