使用mypy对python程序进行静态检查
自从python3.6开始,允许为参数和返回类型添加 type hint,这使得对python程序进行静态检查成为可能。
mypy就是这么一个python type checker.
安装mypy
我们可以使用 pip
来安装mypy。
[lujun9972@T520 work]$ pip install mypy Collecting mypy Downloading mypy-0.570-py3-none-any.whl (1.2MB) 100% |████████████████████████████████| 1.2MB 70kB/s Collecting typed-ast<1.2.0,>=1.1.0 (from mypy) Downloading typed_ast-1.1.0-cp36-cp36m-manylinux1_x86_64.whl (724kB) 100% |████████████████████████████████| 727kB 68kB/s Installing collected packages: typed-ast, mypy Successfully installed mypy-0.570 typed-ast-1.1.0
使用mypy进行静态检查
假设有这么一个 test.py
的文件:
class Student(): def __init__(self,id,name,age,major): self.id = id self.name = name self.age = age self.major = major def display(persons): for person in persons: print(f'{person.id} {person.name}') dark = Student('1', 'Dark', '19', 'computer') sun = Student('2', 'Sun', 21, 'account') lujun= Student(3, 'lujun', 'MBA', 25) display(dark) display([sun, dark, 'lujun'])
这段代码并没有添加 type hint,但是从代码中可以很容易看出是有许多错误的。
我们用 mypy
来检查一下看能不能查出什么:
[lujun9972@T520 work]$ mypy /tmp/test.py [lujun9972@T520 work]$
你会发现 mypy
什么错误都没有提示。
现在我们来为程序加上type hint
from typing import List class Student(): def __init__(self, id:int, name:str, age:int, major:str)->None: self.id = id self.name = name self.age = age self.major = major def display(persons:List[Student])->None: for person in persons: print(f'{person.id} {person.name}') dark = Student('1', 'Dark', '19', 'computer') sun = Student('2', 'Sun', 21, 'account') lujun= Student(3, 'lujun', 'MBA', 25) display(dark) display([sun, dark, 'lujun'])
再次用 mypy
来检查一下
[lujun9972@T520 work]$ mypy /tmp/test_with_type_hint.py /tmp/test_with_type_hint.py:14: error: Argument 1 to "Student" has incompatible type "str"; expected "int" /tmp/test_with_type_hint.py:14: error: Argument 3 to "Student" has incompatible type "str"; expected "int" /tmp/test_with_type_hint.py:15: error: Argument 1 to "Student" has incompatible type "str"; expected "int" /tmp/test_with_type_hint.py:16: error: Argument 3 to "Student" has incompatible type "str"; expected "int" /tmp/test_with_type_hint.py:16: error: Argument 4 to "Student" has incompatible type "int"; expected "str" /tmp/test_with_type_hint.py:18: error: Argument 1 to "display" has incompatible type "Student"; expected "List[Student]" /tmp/test_with_type_hint.py:19: error: List item 2 has incompatible type "str"; expected "Student"
可以发现,找出了一堆问题。
帮助信息
mypy还带有一堆的参数来定义检查的方法,运行 mypy -h
就会列出帮助信息了:
[lujun9972@T520 work]$ mypy --help usage: mypy [-h] [-v] [-V] [--python-version x.y] [--platform PLATFORM] [-2] [--ignore-missing-imports] [--follow-imports {normal,silent,skip,error}] [--disallow-any-unimported] [--disallow-any-expr] [--disallow-any-decorated] [--disallow-any-explicit] [--disallow-any-generics] [--disallow-untyped-calls] [--disallow-untyped-defs] [--disallow-incomplete-defs] [--check-untyped-defs] [--disallow-subclassing-any] [--warn-incomplete-stub] [--disallow-untyped-decorators] [--warn-redundant-casts] [--no-warn-no-return] [--warn-return-any] [--warn-unused-ignores] [--warn-unused-configs] [--show-error-context] [--no-implicit-optional] [-i] [--quick-and-dirty] [--cache-dir DIR] [--cache-fine-grained] [--skip-version-check] [--strict-optional] [--strict-optional-whitelist [GLOB [GLOB ...]]] [--junit-xml JUNIT_XML] [--pdb] [--show-traceback] [--stats] [--inferstats] [--custom-typing MODULE] [--custom-typeshed-dir DIR] [--scripts-are-modules] [--config-file CONFIG_FILE] [--show-column-numbers] [--find-occurrences CLASS.MEMBER] [--strict] [--shadow-file SOURCE_FILE SHADOW_FILE] [--any-exprs-report DIR] [--cobertura-xml-report DIR] [--html-report DIR] [--linecount-report DIR] [--linecoverage-report DIR] [--memory-xml-report DIR] [--txt-report DIR] [--xml-report DIR] [--xslt-html-report DIR] [--xslt-txt-report DIR] [-m MODULE] [-c PROGRAM_TEXT] [-p PACKAGE] [files [files ...]] optional arguments: -h, --help show this help message and exit -v, --verbose more verbose messages -V, --version show program's version number and exit --python-version x.y use Python x.y --platform PLATFORM typecheck special-cased code for the given OS platform (defaults to sys.platform). -2, --py2 use Python 2 mode --ignore-missing-imports silently ignore imports of missing modules --follow-imports {normal,silent,skip,error} how to treat imports (default normal) --disallow-any-unimported disallow Any types resulting from unfollowed imports --disallow-any-expr disallow all expressions that have type Any --disallow-any-decorated disallow functions that have Any in their signature after decorator transformation --disallow-any-explicit disallow explicit Any in type positions --disallow-any-generics disallow usage of generic types that do not specify explicit type parameters --disallow-untyped-calls disallow calling functions without type annotations from functions with type annotations (inverse: --allow-untyped-calls) --disallow-untyped-defs disallow defining functions without type annotations or with incomplete type annotations (inverse: --allow-untyped-defs) --disallow-incomplete-defs disallow defining functions with incomplete type annotations (inverse: --allow-incomplete-defs) --check-untyped-defs type check the interior of functions without type annotations (inverse: --no-check-untyped-defs) --disallow-subclassing-any disallow subclassing values of type 'Any' when defining classes (inverse: --allow-subclassing- any) --warn-incomplete-stub warn if missing type annotation in typeshed, only relevant with --check-untyped-defs enabled (inverse: --no-warn-incomplete-stub) --disallow-untyped-decorators disallow decorating typed functions with untyped decorators (inverse: --allow-untyped-decorators) --warn-redundant-casts warn about casting an expression to its inferred type (inverse: --no-warn-redundant-casts) --no-warn-no-return do not warn about functions that end without returning (inverse: --warn-no-return) --warn-return-any warn about returning values of type Any from non- Any typed functions (inverse: --no-warn-return- any) --warn-unused-ignores warn about unneeded '# type: ignore' comments (inverse: --no-warn-unused-ignores) --warn-unused-configs warn about unused '[mypy-<pattern>]' config sections (inverse: --no-warn-unused-configs) --show-error-context Precede errors with "note:" messages explaining context (inverse: --hide-error-context) --no-implicit-optional don't assume arguments with default values of None are Optional (inverse: --implicit-optional) -i, --incremental enable module cache, (inverse: --no-incremental) --quick-and-dirty use cache even if dependencies out of date (implies --incremental) --cache-dir DIR store module cache info in the given folder in incremental mode (defaults to '.mypy_cache') --cache-fine-grained include fine-grained dependency information in the cache --skip-version-check allow using cache written by older mypy version --strict-optional enable experimental strict Optional checks (inverse: --no-strict-optional) --strict-optional-whitelist [GLOB [GLOB ...]] suppress strict Optional errors in all but the provided files (experimental -- read documentation before using!). Implies --strict-optional. Has the undesirable side-effect of suppressing other errors in non-whitelisted files. --junit-xml JUNIT_XML write junit.xml to the given file --pdb invoke pdb on fatal error --show-traceback, --tb show traceback on fatal error --stats dump stats --inferstats dump type inference stats --custom-typing MODULE use a custom typing module --custom-typeshed-dir DIR use the custom typeshed in DIR --scripts-are-modules Script x becomes module x instead of __main__ --config-file CONFIG_FILE Configuration file, must have a [mypy] section (defaults to mypy.ini) --show-column-numbers Show column numbers in error messages (inverse: --hide-column-numbers) --find-occurrences CLASS.MEMBER print out all usages of a class member (experimental) --strict Strict mode. Enables the following flags: --disallow-untyped-calls, --disallow-untyped-defs, --disallow-incomplete-defs, --check-untyped-defs, --disallow-subclassing-any, --disallow-untyped- decorators, --warn-redundant-casts, --warn-return- any, --warn-unused-ignores, --warn-unused-configs, --no-implicit-optional, --strict-optional --shadow-file SOURCE_FILE SHADOW_FILE Typecheck SHADOW_FILE in place of SOURCE_FILE. report generation: Generate a report in the specified format. --any-exprs-report DIR --cobertura-xml-report DIR --html-report DIR --linecount-report DIR --linecoverage-report DIR --memory-xml-report DIR --txt-report DIR --xml-report DIR --xslt-html-report DIR --xslt-txt-report DIR How to specify the code to type check: -m MODULE, --module MODULE type-check module; can repeat for more modules -c PROGRAM_TEXT, --command PROGRAM_TEXT type-check program passed in as string -p PACKAGE, --package PACKAGE type-check all files in a directory files type-check given files or directories environment variables: MYPYPATH additional module search path