如何读取函数签名及默认参数值?

190 投票
9 回答
124918 浏览
提问于 2025-04-15 21:50

给定一个函数对象,我该如何获取它的签名呢?比如,对于下面这个:

def my_method(first, second, third='something'):
    pass

我想得到 "my_method(first, second, third='something')" 这样的结果。

9 个回答

15

在编程中,有时候我们需要让程序在特定的条件下执行某些操作。比如说,当用户点击一个按钮时,程序就要做出反应。这种情况下,我们会用到“事件监听器”。

事件监听器就像一个守卫,它一直在关注你指定的事件,比如鼠标点击、键盘按下等。当这些事件发生时,守卫就会立刻通知程序去执行相应的操作。

举个例子,假设你在网页上有一个“提交”按钮,你希望用户点击这个按钮后,程序能处理他们输入的数据。你可以设置一个事件监听器来监控这个按钮的点击事件。一旦用户点击了按钮,事件监听器就会触发,程序就会开始处理数据。

总之,事件监听器就是帮助我们在合适的时机做出反应的工具,让程序能够更智能地与用户互动。

#! /usr/bin/env python

import inspect
from collections import namedtuple

DefaultArgSpec = namedtuple('DefaultArgSpec', 'has_default default_value')

def _get_default_arg(args, defaults, arg_index):
    """ Method that determines if an argument has default value or not,
    and if yes what is the default value for the argument

    :param args: array of arguments, eg: ['first_arg', 'second_arg', 'third_arg']
    :param defaults: array of default values, eg: (42, 'something')
    :param arg_index: index of the argument in the argument array for which,
    this function checks if a default value exists or not. And if default value
    exists it would return the default value. Example argument: 1
    :return: Tuple of whether there is a default or not, and if yes the default
    value, eg: for index 2 i.e. for "second_arg" this function returns (True, 42)
    """
    if not defaults:
        return DefaultArgSpec(False, None)

    args_with_no_defaults = len(args) - len(defaults)

    if arg_index < args_with_no_defaults:
        return DefaultArgSpec(False, None)
    else:
        value = defaults[arg_index - args_with_no_defaults]
        if (type(value) is str):
            value = '"%s"' % value
        return DefaultArgSpec(True, value)

def get_method_sig(method):
    """ Given a function, it returns a string that pretty much looks how the
    function signature would be written in python.

    :param method: a python method
    :return: A string similar describing the pythong method signature.
    eg: "my_method(first_argArg, second_arg=42, third_arg='something')"
    """

    # The return value of ArgSpec is a bit weird, as the list of arguments and
    # list of defaults are returned in separate array.
    # eg: ArgSpec(args=['first_arg', 'second_arg', 'third_arg'],
    # varargs=None, keywords=None, defaults=(42, 'something'))
    argspec = inspect.getargspec(method)
    arg_index=0
    args = []

    # Use the args and defaults array returned by argspec and find out
    # which arguments has default
    for arg in argspec.args:
        default_arg = _get_default_arg(argspec.args, argspec.defaults, arg_index)
        if default_arg.has_default:
            args.append("%s=%s" % (arg, default_arg.default_value))
        else:
            args.append(arg)
        arg_index += 1
    return "%s(%s)" % (method.__name__, ", ".join(args))


if __name__ == '__main__':
    def my_method(first_arg, second_arg=42, third_arg='something'):
        pass

    print get_method_sig(my_method)
    # my_method(first_argArg, second_arg=42, third_arg="something")
61

找到一个函数的用法最简单的方法就是用 help(function) 这个命令:

>>> def function(arg1, arg2="foo", *args, **kwargs): pass
>>> help(function)
Help on function function in module __main__:

function(arg1, arg2='foo', *args, **kwargs)

另外,在 Python 3 中,inspect 模块里新增了一个叫 signature 的方法,这个方法专门用来表示一个可调用对象的用法和它的返回值注解:

>>> from inspect import signature
>>> def foo(a, *, b:int, **kwargs):
...     pass

>>> sig = signature(foo)

>>> str(sig)
'(a, *, b:int, **kwargs)'

>>> str(sig.parameters['b'])
'b:int'

>>> sig.parameters['b'].annotation
<class 'int'>
262
import inspect

def foo(a, b, x='blah'):
    pass

print(inspect.signature(foo))
# (a, b, x='blah')

Python 3.5及以上版本建议使用 inspect.signature() 这个功能。

撰写回答