W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
你有一個(gè)函數(shù)或方法,它使用*args和**kwargs作為參數(shù),這樣使得它比較通用,但有時(shí)候你想檢查傳遞進(jìn)來的參數(shù)是不是某個(gè)你想要的類型。
對(duì)任何涉及到操作函數(shù)調(diào)用簽名的問題,你都應(yīng)該使用 inspect
模塊中的簽名特性。我們最主要關(guān)注兩個(gè)類:Signature
和 Parameter
。下面是一個(gè)創(chuàng)建函數(shù)前面的交互例子:
>>> from inspect import Signature, Parameter
>>> # Make a signature for a func(x, y=42, *, z=None)
>>> parms = [ Parameter('x', Parameter.POSITIONAL_OR_KEYWORD),
... Parameter('y', Parameter.POSITIONAL_OR_KEYWORD, default=42),
... Parameter('z', Parameter.KEYWORD_ONLY, default=None) ]
>>> sig = Signature(parms)
>>> print(sig)
(x, y=42, *, z=None)
>>>
一旦你有了一個(gè)簽名對(duì)象,你就可以使用它的 bind()
方法很容易的將它綁定到 *args
和 **kwargs
上去。下面是一個(gè)簡(jiǎn)單的演示:
>>> def func(*args, **kwargs):
... bound_values = sig.bind(*args, **kwargs)
... for name, value in bound_values.arguments.items():
... print(name,value)
...
>>> # Try various examples
>>> func(1, 2, z=3)
x 1
y 2
z 3
>>> func(1)
x 1
>>> func(1, z=3)
x 1
z 3
>>> func(y=2, x=1)
x 1
y 2
>>> func(1, 2, 3, 4)
Traceback (most recent call last):
...
File "/usr/local/lib/python3.3/inspect.py", line 1972, in _bind
raise TypeError('too many positional arguments')
TypeError: too many positional arguments
>>> func(y=2)
Traceback (most recent call last):
...
File "/usr/local/lib/python3.3/inspect.py", line 1961, in _bind
raise TypeError(msg) from None
TypeError: 'x' parameter lacking default value
>>> func(1, y=2, x=3)
Traceback (most recent call last):
...
File "/usr/local/lib/python3.3/inspect.py", line 1985, in _bind
'{arg!r}'.format(arg=param.name))
TypeError: multiple values for argument 'x'
>>>
可以看出來,通過將簽名和傳遞的參數(shù)綁定起來,可以強(qiáng)制函數(shù)調(diào)用遵循特定的規(guī)則,比如必填、默認(rèn)、重復(fù)等等。
下面是一個(gè)強(qiáng)制函數(shù)簽名更具體的例子。在代碼中,我們?cè)诨愔邢榷x了一個(gè)非常通用的 __init__()
方法,然后我們強(qiáng)制所有的子類必須提供一個(gè)特定的參數(shù)簽名。
from inspect import Signature, Parameter
def make_sig(*names):
parms = [Parameter(name, Parameter.POSITIONAL_OR_KEYWORD)
for name in names]
return Signature(parms)
class Structure:
__signature__ = make_sig()
def __init__(self, *args, **kwargs):
bound_values = self.__signature__.bind(*args, **kwargs)
for name, value in bound_values.arguments.items():
setattr(self, name, value)
# Example use
class Stock(Structure):
__signature__ = make_sig('name', 'shares', 'price')
class Point(Structure):
__signature__ = make_sig('x', 'y')
下面是使用這個(gè) Stock
類的示例:
>>> import inspect
>>> print(inspect.signature(Stock))
(name, shares, price)
>>> s1 = Stock('ACME', 100, 490.1)
>>> s2 = Stock('ACME', 100)
Traceback (most recent call last):
...
TypeError: 'price' parameter lacking default value
>>> s3 = Stock('ACME', 100, 490.1, shares=50)
Traceback (most recent call last):
...
TypeError: multiple values for argument 'shares'
>>>
在我們需要構(gòu)建通用函數(shù)庫(kù)、編寫裝飾器或?qū)崿F(xiàn)代理的時(shí)候,對(duì)于 *args
和 **kwargs
的使用是很普遍的。但是,這樣的函數(shù)有一個(gè)缺點(diǎn)就是當(dāng)你想要實(shí)現(xiàn)自己的參數(shù)檢驗(yàn)時(shí),代碼就會(huì)笨拙混亂。在8.11小節(jié)里面有這樣一個(gè)例子。這時(shí)候我們可以通過一個(gè)簽名對(duì)象來簡(jiǎn)化它。
在最后的一個(gè)方案實(shí)例中,我們還可以通過使用自定義元類來創(chuàng)建簽名對(duì)象。下面演示怎樣來實(shí)現(xiàn):
from inspect import Signature, Parameter
def make_sig(*names):
parms = [Parameter(name, Parameter.POSITIONAL_OR_KEYWORD)
for name in names]
return Signature(parms)
class StructureMeta(type):
def __new__(cls, clsname, bases, clsdict):
clsdict['__signature__'] = make_sig(*clsdict.get('_fields',[]))
return super().__new__(cls, clsname, bases, clsdict)
class Structure(metaclass=StructureMeta):
_fields = []
def __init__(self, *args, **kwargs):
bound_values = self.__signature__.bind(*args, **kwargs)
for name, value in bound_values.arguments.items():
setattr(self, name, value)
# Example
class Stock(Structure):
_fields = ['name', 'shares', 'price']
class Point(Structure):
_fields = ['x', 'y']
當(dāng)我們自定義簽名的時(shí)候,將簽名存儲(chǔ)在特定的屬性 __signature__
中通常是很有用的。這樣的話,在使用 inspect
模塊執(zhí)行內(nèi)省的代碼就能發(fā)現(xiàn)簽名并將它作為調(diào)用約定。
>>> import inspect
>>> print(inspect.signature(Stock))
(name, shares, price)
>>> print(inspect.signature(Point))
(x, y)
>>>
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: