Python学习笔记(三)

文章目录

  • 1. 异常
  • 2. 单测
  • 3. 读写文件
    • 3.1 读文件
    • 3.2 写文件
    • 3.3. 操作文件和目录
  • 4. 正则表达式
    • 4.1 贪婪匹配
  • 5. 其它
    • 5.1. StringIO BytesIO
    • 5.2. 序列化
      • 5.2.1 pickle
      • 5.2.2. JSON

供个人学习笔记回顾时使用.

1. 异常

没啥说的, 语法换下而已. 下文只会记录一下和JS语法不同的地方:
基础语法: try...except...finally...

一. 可以expect多个异常, 例子:

可以使用expect语句块处理不同的错误

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

二. expect之后还可以增加else语句, 用来没有错误发生时,执行else语句, 例子:

try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

三. py自带一个logging模块, 可以用来记录错误, 例子:

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')

通过配置,logging还可以把错误记录到日志文件里,方便事后排查。

四. 抛出错误使用raise语法 例子:

def foo(s):
    n = int(s)
    if n==0:
        raise ValueError('invalid value: %s' % s)
    return 10 / n

py错误类型种类介绍

https://docs.python.org/3/library/exceptions.html#exception-hierarchy

2. 单测

python自带单测模块, unittest, 编写单测时需要继承该类.
且命名也有规范,开头必要以test开头, 否则测试的时候不会被执行.
这里有个第一次见到的语法就是下面例子中的with语句, 用来捕获raise
例子如下:

import unittest

class asd(unittest.TestCase):
    def aaa_80_to_100(self):
        s1 = Student('Bart', 80)
        s2 = Student('Lisa', 100)
        self.assertEqual(s1.get_grade(), 'A')
        self.assertEqual(s2.get_grade(), 'A')

    def test_60_to_80(self):
        s1 = Student('Bart', 60)
        s2 = Student('Lisa', 79)
        self.assertEqual(s1.get_grade(), 'B')
        self.assertEqual(s2.get_grade(), 'B')

    def test_0_to_60(self):
        s1 = Student('Bart', 0)
        s2 = Student('Lisa', 59)
        self.assertEqual(s1.get_grade(), 'C')
        self.assertEqual(s2.get_grade(), 'C')

    def test_invalid(self):
        s1 = Student('Bart', -1)
        s2 = Student('Lisa', 101)
        with self.assertRaises(ValueError):
            s1.get_grade()
        with self.assertRaises(ValueError):
            s2.get_grade()

此外py这个单测模块还带了声明周期, 例子与js的mocha模块中beforeEachafterEach功能类似, 如下

class asd(unittest.TestCase):
    def setUp(self):
        print('setUp...')

    def tearDown(self):
        print('tearDown...')
    
    省略第一个列子代码, 输出如下:

setUp...
tearDown...
.setUp...
tearDown...
.setUp...
tearDown...
.
----------------------------------------------------------------------
Ran 3 tests in 0.003s

OK

3. 读写文件

和C, Node的读写文件差不多

3.1 读文件

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

操作文件过程中为了防止raise错误, 导致文件没有关闭需要使用try
try:
    f = open('/path/to/file', 'r')
    print(f.read())
finally:
    if f:
        f.close()

更简洁写法
with open('/path/to/file', 'r') as f:
	f.read()

3.2 写文件

f = open('/Users/michael/test.txt', 'w')
f.write('123')
f.close()
其它语法同上

这种File System Flags可以参考这里:
https://docs.python.org/3/library/functions.html#open

3.3. 操作文件和目录

这一节没什么说的了, 就是函数而已

# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
os.path.join('/Users/michael', 'testdir')
# 然后创建一个目录:
os.mkdir('/Users/michael/testdir')
# 删掉一个目录:
os.rmdir('/Users/michael/testdir')
# 对文件重命名:
os.rename('test.txt', 'test.py')
# 删掉文件:
os.remove('test.py')

4. 正则表达式

感觉这一部分和JS实在太像了, 简单记录下API好了

import re

# 1. 这里使用了'r'之后就可以不管转义的问题
# 2. '^'表示已xx开头
# 3. '$'表示已xx结尾
# 4. '\d{3-8}'表示3-8个数字

m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
# <_sre.SRE_Match object; span=(0, 9), match='010-12345'>

m.group(0) # '010-12345'
m.group(1) # '010'
m.group(2) # '12345'

4.1 贪婪匹配

这个知识点有点忘了, 顺便回顾一下

# '+'表示贪婪匹配尽可能多的匹配字符, 因此后面匹配0位为空
re.match(r'^(\d+)(0*)$', '102300').groups() # ('102300', '')

# '?'可以让\d+采用非贪婪匹配
re.match(r'^(\d+?)(0*)$', '102300').groups() # ('1023', '00')

5. 其它

5.1. StringIO BytesIO

这两个API暂时想不到用途在哪里, 见下面例子:

// 在内存中读写str
from io import StringIO

f = StringIO()
print(f.write('hello')) // 5
print(f.write(' ')) // 1
print(f.write('world!')) // 6
print(f.getvalue()) // hello world!
// 在内存中读写Byte
from io import BytesIO

f = BytesIO()
print(f.write('中文'.encode('utf-8'))) // 6
print(f.getvalue()) // b'\xe4\xb8\xad\xe6\x96\x87'

5.2. 序列化

有两种, 一种是变量序列化, 一种是JSON序列化. 很好理解, 见下方代码

5.2.1 pickle

# 变量序列化

import pickle

# 存到本地文件
d = dict(name='Bob', age=20, score=88)
f = open('dump.txt', 'wb')
pickle.dump(d, f) # 是个二进制数据
f.close()

# 从本地文件读取到内存
f = open('dump.txt', 'rb')
a = pickle.load(f)
f.close()
print(a)

5.2.2. JSON

# JSON序列化

import json

d = dict(name='Bob', age=20, score=88)
json.dumps(d) # 就是JSON.stringify '{"age": 20, "score": 88, "name": "Bob"}'

json_str = '{"age": 20, "score": 88, "name": "Bob"}'
json.loads(json_str) # 就是JSON.parse {'age': 20, 'score': 88, 'name': 'Bob'}

python对于class dumps需要做些特殊处理, 还需要传入第二个参数

class Student(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

s = Student('Bob', 20, 88)
print(json.dumps(s)) # 报错

# 方法1
def student2dict(std):
    return {
        'name': std.name,
        'age': std.age,
        'score': std.score
}
# 需要先把Student实例转换成dict,然后再序列化为JSON
print(json.dumps(s, default=student2dict)) # {"age": 20, "name": "Bob", "score": 88} 

# 方法2
# 或者直接用class的_dict_
print(json.dumps(s, default=lambda obj: obj.__dict__))


# 因此pyhton json的loads方法, 还可以直接把字符串反序列成class
def dict2student(d):
    return Student(d['name'], d['age'], d['score'])

json_str = '{"age": 20, "score": 88, "name": "Bob"}'
print(json.loads(json_str, object_hook=dict2student)) # <__main__.Student object at 0x10cd3c190>

reference links:

  1. 廖雪峰Python学习文档

你可能感兴趣的:(Python)