数据结构或者边界错误时候,直接报错而不是有其他的机制来避免错误影响。
严格来说不算一个坑,只能说是规范性问题。
Python是动态类型语言:
- 不要求提前声明变量类型;
- 不校验访问的的key是否存在;
- 不检测list的边界;
- 不会在编译阶段帮忙报错;
这导致一个问题,就是python经常运行到具体的某行代码时候才会报错。
d = {"name":"shen"}
print(d["age"])
Traceback (most recent call last):
File "<input>", line 1, in <module>
KeyError: 'age'
arr = [1,2,3]
print(arr[10])
Traceback (most recent call last):
File "<input>", line 1, in <module>
IndexError: list index out of range
print(arr["x"])
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: list indices must be integers or slices, not str
data = {"user": {"profile": {"phone": "123"}}}
print(data["user"])
{'profile': {'phone': '123'}}
print(data["user"]["address"]["city"])
Traceback (most recent call last):
File "<input>", line 1, in <module>
KeyError: 'address'
解决方案只能是多注意,三个思路:类型注解、单元测试、mypy静态检查。
(1)类型注解
在代码里写清楚这个变量应该是什么类型,”->”,函数返回类型注解,就是声明这个函数应该返回什么类似数据,当然不强制。”:”,参数类型注解,则表示这个参数应该是字典,当然也不强制。这个工具能够使一些静态工具提前发现问题,在大型项目里提升代码的可读性。
def get_age(user: dict) -> int:
return user["age"]
print(get_age(user))
user = {"age":10,"name":"wang"}
print(get_age(user))
10
user2 = {"age":20,"name":"zhang"}
print(get_age(user2))
20
这个之前项目代码里看到过很多次,每次都吐槽md写个代码怎么折腾那么复杂,现在发现了,原来都是有用的……
(2)单元测试
就是写测试用例,确保函数不会再实际运行时爆炸。assert就是python自带的断言语句【assert 条件表达式, ”报错信息“】。如果条件为True,什么都不做,如果条件为False,抛出AssertionError,就知道是这儿出了问题。
def test_get_age():
user = {"age": 20}
assert get_age(user) == 20
(3)mypy静态检查(static type checking)
安装:pip install mypy
在终端执行:mypy test.py
很有意思的是第一次mypy没有指出错误,似乎因为太宽松了。
# test.py测试文件
def add(x: int, y: int) -> int:
return x + y
def main():
result = add("10", 20) # 故意写错:传了字符串
print(result)
main()
# 控制台:
(hellopython) PS C:\> cd .\Users\13989\Desktop\
(hellopython) PS C:\Users\13989\Desktop> mypy test.py
Success: no issues found in 1 source file
(hellopython) PS C:\Users\13989\Desktop> mypy test.py --strict
test.py:4: error: Function is missing a return type annotation [no-untyped-def]
test.py:4: note: Use "-> None" if function does not return a value
test.py:5: error: Argument 1 to "add" has incompatible type "str"; expected "int" [arg-type]
test.py:8: error: Call to untyped function "main" in typed context [no-untyped-call]
Found 3 errors in 1 file (checked 1 source file)