Python-类型注解(3.5引入)
1、函數(shù)定義的弊端:
Python是動(dòng)態(tài)語(yǔ)言,變量隨時(shí)可以被賦值,且能賦值為不同的類型。
Python不是靜態(tài)編譯型語(yǔ)言,變量類型是在運(yùn)行器決定的
動(dòng)態(tài)語(yǔ)言很靈活,但是這種特性也是弊端:
def add(x, y):return x +yadd(1, 2)add('a', 'b') 都是ok的,但是不是自己想要的,只是數(shù)學(xué)加難發(fā)現(xiàn):由于不做任何類型檢查,知道運(yùn)行期間問題才會(huì)顯現(xiàn)出來,或這上線運(yùn)行時(shí)才能暴露出問題
難使用:函數(shù)的使用者看到函數(shù)的時(shí)候,并不知道你的函數(shù)的設(shè)計(jì),并不知道應(yīng)該傳入什么類型的數(shù)據(jù)
2、如何解決這種動(dòng)態(tài)語(yǔ)言定義的弊端
增加文檔字符串
這只是一個(gè) 管理,不是強(qiáng)制標(biāo)準(zhǔn),不能要求程序員一定為函數(shù)提供說明文檔。
函數(shù)定義更新了,文檔未必同步更新
''' 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' def add(x, y):''':param x::param y::return:'''return x + y print(help(add))3、函數(shù)注解 Function Annotations
舉例 1:
函數(shù)注解總結(jié):
Python3.5 引入的
對(duì)函數(shù)的參數(shù)進(jìn)行類型注解
對(duì)函數(shù)的返回值進(jìn)行類型注解
只對(duì)函數(shù)參數(shù)做一個(gè)輔助的說明,并不對(duì)函數(shù)的參數(shù)進(jìn)行類型檢查
提供第三方工具,做代碼分析,如上所述的Pycharm
函數(shù)注解的信息,保存在__annotations__ 屬性中
print(add.annotations) # {‘x’: <class ‘int’>, ‘y’: <class ‘int’>, ‘return’: <class ‘int’>} # 是有序的字典,3.6 之后
變量注解:
Python 3.6 引入的 i : int = 3
4、業(yè)務(wù)應(yīng)用:
函數(shù)參數(shù)檢查:
思路:
函數(shù)的參數(shù)的檢查,一定是在函數(shù)外
函數(shù)應(yīng)該作為參數(shù),傳入到檢查的函數(shù)中
檢查函數(shù)拿到函數(shù)傳入的時(shí)間參數(shù)與形參聲明對(duì)比。
__annotations__屬性是一個(gè)字典,其中包括返回值類型的聲明,假設(shè)要做位置參數(shù)的判斷,無法和字典中的聲明對(duì)應(yīng),使用inspect模塊。
inspect模塊:
提供獲取對(duì)象信息的函數(shù),可以經(jīng)檢查函數(shù) 和 類 , 類型檢查。
5、inspect 模塊
# NO 1 引入inspect 模塊,獲取函數(shù) 簽名 以及 參數(shù)(形參) 類型注解# inspect.isfunction(object) 是否是函數(shù) # inspect.isclass(object) 是否是類 # inspect.ismethod() 是否是類的方法 # inspect.isfunction() 是否是函數(shù) # inspect.isgenerator() 是否是生成器對(duì)象 # inspect.isgeneratorfunction() 是否是生成器函數(shù) ''' 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' import inspectdef add(x:int, y:int) -> int:# 返回值的注解return x + yprint(add.__name__) # 返回的是 str類型 ‘a(chǎn)dd'print(inspect.isfunction(add)) # True 是函數(shù),可以用來判斷sig = inspect.signature(add) print(sig) # (x: int, y: int) -> int 簽名print(add.__annotations__,'---------')# {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>} ---------params = sig.parameters # 獲取參數(shù),以及參數(shù)類型注解 print(params) # OrderedDict([('x', <Parameter "x: int">), ('y', <Parameter "y: int">)]) # 3.6之后使用了有序字典,所以是有順序的!!! # 注意 key 是字符串,并不是形參的標(biāo)識(shí)符,并不是把形參str(x) 這是不對(duì)的!這是把x對(duì)應(yīng)的值給類型轉(zhuǎn)換,并不是'x' # 基本概念要清楚!# 參數(shù)類型 (內(nèi)置的一種新類型) for i, (k,param) in enumerate(params.items()):print(i,k, param) # from inspect import Parameter # param:Parameter ##變量類型注解,在pycharm 中就可以用 點(diǎn) 就可以獲取下拉列表# 上面的這兩句只是為了獲取 屬性,免得去查 幫助,即:參數(shù)類型 的 屬性print(param.name, param.default, param.annotation, param.kind) # 0 x x: int # x <class 'inspect._empty'> <class 'int'> POSITIONAL_OR_KEYWORD ''' x 是 參數(shù)名----默認(rèn)值是 空--------參數(shù)的屬性注解 -------形參類型 位置參數(shù)或者關(guān)鍵字''' # 1 y y: int # y <class 'inspect._empty'> <class 'int'> POSITIONAL_OR_KEYWORDprint('+' , params['x'].annotation) print('+' , params['x'])def a(*args, **kwargs): # args 只有名字 和passsig = inspect.signature(a) print(sig) params = sig.parameters print(params) for k,v in params.items():print(v.name,v.default,v.annotation,v.kind) # (*args, **kwargs) # OrderedDict([('args', <Parameter "*args">), ('kwargs', <Parameter "**kwargs">)]) # args <class 'inspect._empty'> <class 'inspect._empty'> VAR_POSITIONAL # # kwargs <class 'inspect._empty'> <class 'inspect._empty'> VAR_KEYWORDsignature(callable) 獲取簽名(函數(shù)簽名包含了一個(gè)函數(shù)的信息,包括函數(shù)名,他的參數(shù)類型,它所在的類和命名空間及其他信息)
Parameter 對(duì)象:
保存在元組中,是只讀的
name,參數(shù)名字
annotation,參數(shù)的直接,可能沒有定義
default,參數(shù)的缺省值,可能沒有定義
empty,特殊的類,用來標(biāo)記default 屬性或者注釋annotation屬性的空值
kind,實(shí)參如何綁定到形參,值必須是位置參數(shù)提供
POSITION_ONLY 值必須是位置參數(shù)提供,事實(shí)上,python中沒有,被下一項(xiàng)包括
POSITION_OR_KEYWORD 值可以作為關(guān)鍵字或者位置參數(shù)提供
VAR_POSITIONAL 勒邊位置參數(shù),對(duì)應(yīng)args
KEYWORD_ONLY 對(duì)應(yīng) 或者*args之后出現(xiàn)的非可變關(guān)鍵字參數(shù)
VAR_KEYWORD 可變關(guān)鍵字參數(shù),對(duì)應(yīng)**kwargs
6、參數(shù)檢查的實(shí)現(xiàn)
''' 遇到問題沒人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:579817333 尋找有志同道合的小伙伴,互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' NO 2 類型檢查 import inspect import timedef check(fn):def wrapper(*args, **kwargs):sig = inspect.signature(fn) # 簽名params = sig.parameters # 有序字典values = list(params.values()) # 參數(shù)類型flag = Truefor i,x in enumerate(args):param:Parameter = values[i]if not isinstance(x, param.annotation):print(x,'not')flag = False #只要發(fā)現(xiàn)一個(gè)就不要往后了else:print(x,'ok')if not flag:raise TypeError('sssss')return fn(*args, **kwargs)return wrapper@check def add(x:int, y:int=6) -> int:return x + yadd(4,5) # 4 ok # 5 ok# NO2 import inspect import timedef check(fn):def wrapper(*args, **kwargs):sig = inspect.signature(fn) # 簽名params = sig.parameters # 有序字典values = list(params.values()) # 參數(shù)類型flag = Truefor i,x in enumerate(args):param:Parameter = values[i]if not isinstance(x, param.annotation):print(x,'not')flag = False #只要發(fā)現(xiàn)一個(gè)就不要往后了else:print(x,'ok')for k,v in kwargs.items():param: Parameter = params[k]# 如果參數(shù)注解為空 inspect._empty 或者寫成 param.emptyif param.annotation != inspect._empty and not isinstance(v, param.annotation):print(v, 'not---')else:print(v, 'ok-----')# if not flag:# raise TypeError('sssss')return fn(*args, **kwargs)return wrapper# @check # def add(x, y:int=6) -> int: # return x + y # # # add(x=4,y=5) # # 4 ok----- # # 5 ok-----# @check # def add(x:int, y:int=6) -> int: # return x + y # # # add(4,y=5) # # 4 ok # # 5 ok----- # # @check # def add(x:str, y:int=6) -> int: # return x + y # # # add(4,y=5) # # 4 not # # 5 ok-----補(bǔ):insect 的is 函數(shù)
inspect.ismodule(object) Return true if the object is a module.inspect.isclass(object) Return true if the object is a class, whether built-in or created in Python code.inspect.ismethod(object) Return true if the object is a bound method written in Python.inspect.isfunction(object) Return true if the object is a Python function, which includes functions created by a lambda expression.inspect.isgeneratorfunction(object) Return true if the object is a Python generator function.inspect.isgenerator(object) Return true if the object is a generator.inspect.iscoroutinefunction(object) Return true if the object is a coroutine function (a function defined with an async def syntax).New in version 3.5.inspect.iscoroutine(object) Return true if the object is a coroutine created by an async def function.New in version 3.5.inspect.isawaitable(object) Return true if the object can be used in await expression.Can also be used to distinguish generator-based coroutines from regular generators:New in version 3.5.inspect.isasyncgenfunction(object) Return true if the object is an asynchronous generator function, for example:New in version 3.6.inspect.isasyncgen(object) Return true if the object is an asynchronous generator iterator created by an asynchronous generator function.New in version 3.6.inspect.istraceback(object) Return true if the object is a traceback.inspect.isframe(object) Return true if the object is a frame.inspect.iscode(object) Return true if the object is a code.inspect.isbuiltin(object) Return true if the object is a built-in function or a bound built-in method.inspect.isroutine(object) Return true if the object is a user-defined or built-in function or method.inspect.isabstract(object) Return true if the object is an abstract base class.inspect.ismethoddescriptor(object) Return true if the object is a method descriptor, but not if ismethod(), isclass(), isfunction() or isbuiltin() are true.總結(jié)
以上是生活随笔為你收集整理的Python-类型注解(3.5引入)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python元编程详解
- 下一篇: Python-functools (re