python 类型注解
<h2>函数定义的弊端</h2><ul>
<li>python 是动态语言,变量随时可以被赋值,且能赋值为不同类型</li>
<li>python 不是静态编译型语言,变量类型是在运行器决定的</li>
<li>动态语言很灵活,但是这种特性也是弊端</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> add(x,y):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(add(4,5<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(add(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">world</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(add(4,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">'</span>)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">报错,TypeError: unsupported operand type(s) for +: 'int' and 'str'</span></pre>
</div>
<ul>
<li>难发现:由于不做任何类型检查,直到运行期问题才显现出来,或者线上运行时才能暴露出问题</li>
<li>难使用:函数的使用者看到函数的时候,并不知道你的函数的设计,并不知道应该传入什么类型数据</li>
</ul>
<p>如何解决这种动态语言定义的弊端呢?</p>
<ul>
<li>增加文档Docmentation String
<ul>
<li>这是一个惯例,不是强制标准,不能要求程序员一定为函数提供说明文档</li>
<li>函数定义更新了,文档未必同步更新</li>
</ul>
</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> add(x,y):
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
:param x:int
:param y:int
:return:int
</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(help(add))</pre>
</div>
<ul>
<li>函数注解
<ul>
<li>python3.5引入</li>
<li>对函数的参数进行类型注解</li>
<li>对函数的返回值进行类型注解</li>
<li>只对函数参数做一个辅助说明,并不对函数参数进行类型检查</li>
<li>提供给第三方工具,做代码分析,发现隐形bug</li>
<li>函数注解的信息,保存在__annotations__属性中</li>
<li>python3.6中引入变量注解
<ul>
<li>i:int = 3</li>
</ul>
</li>
</ul>
</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> add(x:int,y:int)->int:
</span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
:param x:int
:param y:int
:return:int
</span><span style="color: rgba(128, 0, 0, 1)">"""</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y
</span><span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)">(help(add))
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(add(4,5<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(add(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">jax</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">zhai</span><span style="color: rgba(128, 0, 0, 1)">"</span>)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">在pycharm里参数是灰色</span></pre>
</div>
<h2>函数参数类型检查</h2>
<p>思路:</p>
<ul>
<li>函数参数的检查,一定是在函数外</li>
<li>函数应该作为参数,传入到检查函数中</li>
<li>检查函数拿到函数传入的实际参数,与形参声明对比</li>
<li>__annotations__属性是一个字典,其中包括返回值类型的声明,假设要做一个位置参数的判断,无法和字典中的声明对应,使用inspect模块</li>
<li>inspect模块
<ul>
<li>提供获取对象信息的函数,可以检查函数和类、类型检查</li>
</ul>
</li>
</ul>
<p>inspect模块</p>
<ul>
<li>signature(callable),获取签名(函数签名包含一个函数的信息,包括函数名、它的参数类型、它所在的类和名称空间及其他信息)</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> inspect
</span><span style="color: rgba(0, 0, 255, 1)">def</span> add(x:int,y:int,*args,**kwargs)-><span style="color: rgba(0, 0, 0, 1)">int:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y
sig </span>=<span style="color: rgba(0, 0, 0, 1)">inspect.signature(add)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sig,type(sig)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">获取签名</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">params :</span><span style="color: rgba(128, 0, 0, 1)">'</span>,sig.parameters) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">OrderedDict</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">return :</span><span style="color: rgba(128, 0, 0, 1)">'</span>,sig.return_annotation) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">返回值类型</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">y</span><span style="color: rgba(128, 0, 0, 1)">'</span>], type(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">y</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">]))
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">x</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">].annotation)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">args</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">args</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">].annotation)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kwargs</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sig.parameters[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kwargs</span><span style="color: rgba(128, 0, 0, 1)">'</span>].annotation)</pre>
</div>
<div class="cnblogs_code">
<pre>inspect.isfunction(add) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">是不是函数</span>
inspect.ismethod(add) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">是不是类方法</span>
inspect.isgenerator(add) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">是不是生成器</span>
inspect.isclass(add) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">是不是类</span>
inspect.ismodule(add) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">是不是模块</span>
inspect.isbuiltin(add) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">是不是内建对象</span></pre>
</div>
<ul>
<li>Parameter对象
<ul>
<li>保存在元组中,是只读的</li>
<li>name ,参数的名字</li>
<li>annotation 参数注解,可能没有定义</li>
<li>default 参数的缺省值,可能没有定义</li>
<li>empty 特殊的类,用来标记default属性或者注释annotation属性的空值</li>
<li>kind 实参如何绑定到形参,就是形参的类型
<ul>
<li>POSITIONAL_ONLY,值必须是位置参提供</li>
<li>POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供</li>
<li>VAR_POSITIONAL,可变位置参数,对应*args</li>
<li>KEYWORD_ONLY,keyword-only参数,对应*或者*args之后的出现的非可变关键字参数</li>
<li>VAR_KEYWORD,可变关键字参数,对应**kwargs</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>举例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> inspect
</span><span style="color: rgba(0, 0, 255, 1)">def</span> add(x:int,y:int,*args,**kwargs)-><span style="color: rgba(0, 0, 0, 1)">int:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> x+<span style="color: rgba(0, 0, 0, 1)">y
sig </span>=<span style="color: rgba(0, 0, 0, 1)">inspect.signature(add)
</span><span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)">(sig)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">params : </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">, sig.parameters)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">return : </span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">, sig.return_annotation)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">~~~~~~~~~~~~~~~~</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i,item <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> enumerate(sig.parameters.items()):
name,param </span>=<span style="color: rgba(0, 0, 0, 1)"> item
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(i+1<span style="color: rgba(0, 0, 0, 1)">,name,param.annotation,param.kind,param.default)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(param.default <span style="color: rgba(0, 0, 255, 1)">is</span> param.empty, end = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">\n\n</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>有函数如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">def</span> add(x,y:int=7) -><span style="color: rgba(0, 0, 0, 1)"> int:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> x + y</pre>
</div>
<ul>
<li>检查用户输入是否符合参数注解的要求?</li>
<li>思路:
<ul>
<li>调用时,判断用户输入的实参是否符合要求</li>
<li>调用时,用户感觉上还是在调用add函数</li>
<li>对用户输入的数据和声明的类型进行对比,如果不符合,提示用户</li>
</ul>
</li>
</ul>
<p> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> check(fn):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> wrapper(*args,**<span style="color: rgba(0, 0, 0, 1)">kwargs):
sig </span>=<span style="color: rgba(0, 0, 0, 1)"> inspect.signature(fn)
params </span>=<span style="color: rgba(0, 0, 0, 1)"> sig.parameters
values </span>=<span style="color: rgba(0, 0, 0, 1)"> list(params.values())
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">print(values)</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> i,p <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> enumerate(args):
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> print(i,p)</span>
params =<span style="color: rgba(0, 0, 0, 1)"> values
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">print(params.annotation,params.empty)</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> params.annotation <span style="color: rgba(0, 0, 255, 1)">is</span> <span style="color: rgba(0, 0, 255, 1)">not</span> params.empty <span style="color: rgba(0, 0, 255, 1)">and</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> isinstance(p,params.annotation):
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(p,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">!==</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,values.annotation)
</span><span style="color: rgba(0, 0, 255, 1)">for</span> k,v <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> kwargs.items():
</span><span style="color: rgba(0, 0, 255, 1)">if</span> sig.parameters.annotation <span style="color: rgba(0, 0, 255, 1)">is</span> <span style="color: rgba(0, 0, 255, 1)">not</span> inspect._empty <span style="color: rgba(0, 0, 255, 1)">and</span> <span style="color: rgba(0, 0, 255, 1)">not</span><span style="color: rgba(0, 0, 0, 1)"> isinstance(v,sig.parameters.annotation):
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(k,v,<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">!===</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">,sig.parameters.annotation)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> fn(*args,**<span style="color: rgba(0, 0, 0, 1)">kwargs)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> wrapper
@check
</span><span style="color: rgba(0, 0, 255, 1)">def</span> add(x,y:int=7) -><span style="color: rgba(0, 0, 0, 1)"> int:
</span><span style="color: rgba(0, 0, 255, 1)">return</span> x +<span style="color: rgba(0, 0, 0, 1)"> y
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">print(add(20,10))</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(add(20,y=10<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(add(y=10,x=20))</pre>
</div>
<p> </p>
</div>
<div id="MySignature" role="contentinfo">
碎片化时间学习和你一起终身学习<br><br>
来源:https://www.cnblogs.com/xzkzzz/p/11378842.html
頁:
[1]