简体   繁体   English

确定 function 的 arguments 和关键字 arguments

[英]Determine the arguments and keyword arguments of a function

How you determine the form of a valid call to a function?您如何确定对 function 的有效调用的形式?

For example, say we have a function info that accomplishes this;例如,假设我们有一个 function info可以完成此操作; info might work like this (I'm open to suggestions on whatever might be a more complete and more consistent way to represent the information returned): info可能像这样工作(我愿意接受有关表示返回信息的更完整和更一致的方式的建议):

def foo():
    pass

info(foo)
# { 'args': (), 'kwargs': {} }

def bar(a):
    pass

info(bar)
# { 'args': ('a',), 'kwargs': {} }

def baz(a, b=42):
    pass

info(baz)
# { 'args': ('a',), 'kwargs': { 'b': 42 } }

def qux(a, *args, b=42, **kwargs):
    pass

info(qux)
# { 'args': ('a',), 'kwargs': { 'b': 42 }, 'optional': {'*args', '**kwargs'} }

The info function should work for any function. info function 应该适用于任何 function。 I am not sure how to write an example return for every pattern: For example, help(range.__init__) displays我不确定如何为每个模式编写示例返回:例如, help(range.__init__)显示

# __init__(self, /, *args`, **kwargs)

and I am not sure what the / means.我不确定/是什么意思。

The return from info needs to be something that be computed on (with reasonable effort) for the production of arbitrary, correct calls to info 's argument, eg, for randomized testing. info的返回值需要经过计算(通过合理的努力),以产生对info参数的任意、正确的调用,例如,用于随机测试。

There is already a function for this purpose, inspect.getfullargspec which returns namedtuples :已经有一个 function 为此目的, inspect.getfullargspec返回namedtuples

>>> import inspect
>>> inspect.getfullargspec(foo)
FullArgSpec(args=[], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
>>> inspect.getfullargspec(qux)
FullArgSpec(args=['a'], varargs='args', varkw='kwargs', defaults=None, kwonlyargs=['b'], kwonlydefaults={'b': 42}, annotations={})
>>> inspect.getfullargspec(bar)
FullArgSpec(args=['a'], varargs=None, varkw=None, defaults=None, kwonlyargs=[], kwonlydefaults=None, annotations={})
>>> inspect.getfullargspec(baz)
FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(42,), kwonlyargs=[], kwonlydefaults=None, annotations={})

However, if you want, you can build a function from this:但是,如果你愿意,你可以从这里构建一个 function:

def info(func):
    """returns function argument info"""
    specs = inspect.getfullargspec(func)
    dict_ = {}
    dict_['args'] = tuple(specs.args)
    dict_['kwargs'] = {} if specs.kwonlydefaults is None else specs.kwonlydefaults
    dict_['optional'] = set()
    dict_['defaults'] = {} if specs.defaults is None else specs.defaults
    if specs.varargs is not None:
        dict_['optional'].add(f"*{specs.varargs}")
    if specs.varkw is not None:
        dict_['optional'].add(f"*{specs.varkw}")
    if not dict_['optional']:
        dict_['optional'] = {}
    return dict_

>>> info(foo)
{'args': (), 'kwargs': {}, 'optional': {}, 'defaults': {}}

>>> info(qux)
{'args': ('a',), 'kwargs': {'b': 42}, 'optional': {'*args', '*kwargs'}, 'defaults': {}}

>>> info(bar)
{'args': ('a',), 'kwargs': {}, 'optional': {}, 'defaults': {}}

>> info(baz)
{'args': ('a', 'b'), 'kwargs': {}, 'optional': {}, 'defaults': (42,)}

The 42 in baz is not a keyword argument, it is a default one. baz中的42不是关键字参数,而是默认参数。 Because while calling it is not necessary to provide the keyword b .因为在调用时不需要提供关键字b

The * in the help(__init__) refers to keyword only parameters to follow, ie it tells the following arguments must be keyword-only arguments, and similarly any argument preceding / has to be positional argument , for more see PEP457 , PEP570 , PEP3102 . help(__init__)中的*指的是要遵循的仅关键字参数,即它告诉以下 arguments 必须是keyword-only arguments,类似地, /之前的任何参数都必须是positional argument ,更多信息请参见PEP457PEP570PEP3102

Many of these information can be obtained form the inherent code object of the function, which has following attributes:其中许多信息可以从 function 的固有code object 中获得,它具有以下属性:

for attr in dir(qux.__code__):
    if not attr.startswith('_'):
        print(attr,':',getattr(qux.__code__, attr))

co_argcount : 1
co_cellvars : ()
co_code : b'd\x00S\x00'
co_consts : (None,)
co_filename : <ipython-input-43-6608913c4d65>
co_firstlineno : 1
co_flags : 79
co_freevars : ()
co_kwonlyargcount : 1
co_lnotab : b'\x00\x01'
co_name : qux
co_names : ()
co_nlocals : 4
co_stacksize : 1
co_varnames : ('a', 'b', 'args', 'kwargs')

However, these are not descriptive enough, nor easy to access and intended for internal use for python.但是,这些描述性不够,也不容易访问,并且仅供 python 内部使用。 Hence unless you absolutely need a custom function, inspect.getfullargspec is probably the best option.因此,除非您绝对需要自定义 function, inspect.getfullargspec可能是最佳选择。

Output of fullargspec being a namedtuple you can access different fields easily: namedtuplefullargspec是一个命名元组,您可以轻松访问不同的字段:

>>> argspecs = inspect.getfullargspec(qux)
>>> argspecs.args
['a']
>>> argspecs.kwonlydefaults
{'b': 42}

And if you want a dict you can call the _asdict method of the resulting namedtuple :如果你想要一个字典,你可以调用生成的namedtuple_asdict方法:

>>> inspect.getfullargspec(qux)._asdict()  #gives OrderedDict
OrderedDict([('args', ['a']),
             ('varargs', 'args'),
             ('varkw', 'kwargs'),
             ('defaults', None),
             ('kwonlyargs', ['b']),
             ('kwonlydefaults', {'b': 42}),
             ('annotations', {})])
>>> dict(inspect.getfullargspec(qux)._asdict()) #call dict to get regular dict
{'args': ['a'],
 'varargs': 'args',
 'varkw': 'kwargs',
 'defaults': None,
 'kwonlyargs': ['b'],
 'kwonlydefaults': {'b': 42},
 'annotations': {}}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM