供个人学习笔记回顾时使用.
没啥说的, 语法换下而已. 下文只会记录一下和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
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
模块中beforeEach
和afterEach
功能类似, 如下
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
和C, Node的读写文件差不多
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()
f = open('/Users/michael/test.txt', 'w')
f.write('123')
f.close()
其它语法同上
这种File System Flags可以参考这里:
https://docs.python.org/3/library/functions.html#open
这一节没什么说的了, 就是函数而已
# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
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')
感觉这一部分和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'
这个知识点有点忘了, 顺便回顾一下
# '+'表示贪婪匹配尽可能多的匹配字符, 因此后面匹配0位为空
re.match(r'^(\d+)(0*)$', '102300').groups() # ('102300', '')
# '?'可以让\d+采用非贪婪匹配
re.match(r'^(\d+?)(0*)$', '102300').groups() # ('1023', '00')
这两个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'
有两种, 一种是变量序列化, 一种是JSON序列化. 很好理解, 见下方代码
# 变量序列化
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)
# 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: