9.16 args和*kwargs的强制参数签名

    对任何涉及到操作函数调用签名的问题,你都应该使用 模块中的签名特性。我们最主要关注两个类:SignatureParameter 。下面是一个创建函数前面的交互例子:

    一旦你有了一个签名对象,你就可以使用它的 bind() 方法很容易的将它绑定到 *kwargs 上去。下面是一个简单的演示:

    1. >>> def func(*args, **kwargs):
    2. ... bound_values = sig.bind(*args, **kwargs)
    3. ... for name, value in bound_values.arguments.items():
    4. ... print(name,value)
    5. ...
    6. >>> # Try various examples
    7. >>> func(1, 2, z=3)
    8. x 1
    9. y 2
    10. z 3
    11. >>> func(1)
    12. x 1
    13. >>> func(1, z=3)
    14. x 1
    15. z 3
    16. >>> func(y=2, x=1)
    17. y 2
    18. >>> func(1, 2, 3, 4)
    19. Traceback (most recent call last):
    20. ...
    21. File "/usr/local/lib/python3.3/inspect.py", line 1972, in _bind
    22. raise TypeError('too many positional arguments')
    23. TypeError: too many positional arguments
    24. >>> func(y=2)
    25. Traceback (most recent call last):
    26. ...
    27. File "/usr/local/lib/python3.3/inspect.py", line 1961, in _bind
    28. raise TypeError(msg) from None
    29. TypeError: 'x' parameter lacking default value
    30. >>> func(1, y=2, x=3)
    31. Traceback (most recent call last):
    32. ...
    33. File "/usr/local/lib/python3.3/inspect.py", line 1985, in _bind
    34. '{arg!r}'.format(arg=param.name))
    35. TypeError: multiple values for argument 'x'

    下面是一个强制函数签名更具体的例子。在代码中,我们在基类中先定义了一个非常通用的 init() 方法,然后我们强制所有的子类必须提供一个特定的参数签名。

    下面是使用这个 类的示例:

    1. >>> import inspect
    2. >>> print(inspect.signature(Stock))
    3. (name, shares, price)
    4. >>> s1 = Stock('ACME', 100, 490.1)
    5. >>> s2 = Stock('ACME', 100)
    6. Traceback (most recent call last):
    7. ...
    8. TypeError: 'price' parameter lacking default value
    9. >>> s3 = Stock('ACME', 100, 490.1, shares=50)
    10. Traceback (most recent call last):
    11. ...
    12. TypeError: multiple values for argument 'shares'
    13. >>>

    在最后的一个方案实例中,我们还可以通过使用自定义元类来创建签名对象。下面演示怎样来实现:

    当我们自定义签名的时候,将签名存储在特定的属性 中通常是很有用的。这样的话,在使用 inspect 模块执行内省的代码就能发现签名并将它作为调用约定。

    1. >>> import inspect
    2. >>> print(inspect.signature(Stock))
    3. (name, shares, price)
    4. >>> print(inspect.signature(Point))
    5. (x, y)
    6. >>>