使用裝飾器進行函式型別檢查

2021-10-04 00:21:52 字數 2897 閱讀 8086

動態型別的特性使得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 ...