動態型別的特性使得python函式在被呼叫時,其引數型別不易被知曉。或者,為了動態支援多型別,實際引數的型別由呼叫者提供。如下:
def add(x, y):
return x + y
print(add(2, 3)) # 5
print(add('hello', ' world')) # hello world
上面的例子可以看出,函式引數並沒有指定型別,使得該函式支援多種型別,這也正是python語言的特殊之處。
但有時候,我們想限制函式的引數型別。這時很多人會想到型別提示(type hinting),即型別註解。如下:
def add(x:str, y:str) -> str:
return x + y
然而,型別提示僅僅作為程式設計規約。在實際呼叫中無法強制型別約束,也不會有任何報錯,如下:
print(add(2, 3)) # 5
若要強制型別檢查,只能在程式設計中進行型別檢查,然後進行異常提示。**如下:
from inspect import signature
from functools import wraps
def typeassert(*ty_args, **ty_kwargs):
def decorate(func):
# if in optimized mode, disable type checking
if not __debug__:
return func
# map function argument names to supplied types
sig = signature(func)
bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
@wraps(func)
bound_values = sig.bind(*args, **kwargs).arguments
# enforce type assertions across supplied arguments
for name, value in bound_values.items():
if name in bound_types:
if not isinstance(value, bound_types[name]):
raise typeerror('argument {} must be {}'.format(name, bound_types[name]))
return func(*args, **kwargs)
return decorate
@typeassert(int, int)
def add(x, y):
return x + y
@typeassert(int, z=int)
def spam(x, y, z=42):
print(x, y, z)
>>> spam(1, 2, 3)
12 3
>>> spam(1, 'hello', 3)
1 hello 3
>>> spam(1, 'hello', 'world') t
raceback (most recent call last):
typeerror: argument z must be >>>
編寫此裝飾器的乙個棘手的部分是,它涉及檢查並使用要包裝的函式的引數簽名。 此處選擇的工具應該是inspect.signature()函式。 簡而言之,它允許從可呼叫物件中提取簽名資訊。
如下:
>>> from inspect import signature
>>> def spam(x, y, z=42):
... pass
...>>> sig = signature(spam)
>>> print(sig)
(x, y, z=42)
>>> sig.parameters
'y': ,
'z': })
>>> sig.parameters['z'].name
'z'>>> sig.parameters['z'].default
42>>> sig.parameters['z'].kind
<_parameterkind.positional_or_keyword: 1>
>>>
在裝飾器的第一部分,使用signature物件的bind_partial()方法對提供的型別與引數名稱進行部分繫結。
>>> bound_types = sig.bind_partial(int,z=int)
>>> bound_types
, z=)>
>>> bound_types.arguments
ordereddict([('x', ), ('z', )])
>>>
在此部分繫結中,會注意到丟失的引數將被忽略(即,引數y沒有繫結)。 但是,繫結的最重要部分是建立有序字典bound_types.arguments。 該字典以與函式簽名相同的順序將引數名稱對映到提供的值。 對於我們的裝飾器,此對映包含我們要強制執行的型別斷言。
在裝飾器執行的實際包裝函式中,使用sig.bind()方法。 bind()類似於bind_partial(),不同之處在於它不允許缺少引數。 因此,發生了以下情況:
>>> bound_values = sig.bind(1, 2, 3)
>>> bound_values.arguments
ordereddict([('x', 1), ('y', 2), ('z', 3)])
>>>
Python裝飾器實現函式動態型別檢查
import inspect import functools def typehints fn functools.wraps fn def wrap args,kwargs sig inspect.signature fn params sig.parameters 處理kwargs 字典 fo...
PropTypes進行型別檢查
注意 react.proptypes 已經廢棄,請使用 prop types 庫來代替.隨著應用日漸龐大,我們可以通過型別檢查捕獲大量錯誤.對於某些應用來說,你還可以使用 flow 或 typescript 這樣的 js 擴充套件來對整個應用程式進行型別檢查.然而即使不用他們,react 也有一些內...
python裝飾器 如何使用函式裝飾器
問題舉例 有時候我們想為多個函式統一新增某種功能,比如計時統計 記錄日誌,快取運算結果等 我們並不想在每個函式內一一新增完全相同的 有什麼解決方案嗎?定義裝飾器函式,用它在原函式的基礎上生成乙個新增新功能的函式來代替原函式 def memo func cache def wrap args res ...