确定函数的参数和关键字参数
Determine the arguments and keyword arguments of a function
如何确定函数的有效调用形式?
例如,假设我们有一个函数 info
可以完成此任务; info
可能 是这样工作的(我愿意接受任何关于更完整和更一致的信息表示方式的建议 returned):
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'} }
info
函数应该适用于任何函数。我不确定如何为每个模式编写示例 return:例如,help(range.__init__)
显示
# __init__(self, /, *args`, **kwargs)
我不确定 /
是什么意思。
info
中的 return 需要计算(通过合理的努力)来生成任意的 correct 调用 info
的参数,例如,用于随机测试。
已经有用于此目的的函数,inspect.getfullargspec
which returns 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={})
但是,如果您愿意,可以从中构建一个函数:
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,)}
baz
中的42
不是关键字参数,而是默认参数。因为调用时不需要提供关键字 b
.
help(__init__)
中的 *
指的是要跟随的仅关键字参数,即它告诉后面的参数必须是 keyword-only
个参数,类似地,任何在 [=23= 之前的参数] 必须是 positional argument
,有关更多信息,请参阅 PEP457
, PEP570
, PEP3102
。
许多这些信息可以从函数的固有 code
对象中获得,它具有以下属性:
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')
但是,这些内容描述性不够,也不容易访问且仅供 python 内部使用。因此,除非您绝对需要自定义函数,否则 inspect.getfullargspec
可能是最佳选择。
fullargspec
的输出是 namedtuple
您可以轻松访问不同的字段:
>>> argspecs = inspect.getfullargspec(qux)
>>> argspecs.args
['a']
>>> argspecs.kwonlydefaults
{'b': 42}
如果你想要一个字典,你可以调用结果 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': {}}
如何确定函数的有效调用形式?
例如,假设我们有一个函数 info
可以完成此任务; info
可能 是这样工作的(我愿意接受任何关于更完整和更一致的信息表示方式的建议 returned):
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'} }
info
函数应该适用于任何函数。我不确定如何为每个模式编写示例 return:例如,help(range.__init__)
显示
# __init__(self, /, *args`, **kwargs)
我不确定 /
是什么意思。
info
中的 return 需要计算(通过合理的努力)来生成任意的 correct 调用 info
的参数,例如,用于随机测试。
已经有用于此目的的函数,inspect.getfullargspec
which returns 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={})
但是,如果您愿意,可以从中构建一个函数:
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,)}
baz
中的42
不是关键字参数,而是默认参数。因为调用时不需要提供关键字 b
.
help(__init__)
中的 *
指的是要跟随的仅关键字参数,即它告诉后面的参数必须是 keyword-only
个参数,类似地,任何在 [=23= 之前的参数] 必须是 positional argument
,有关更多信息,请参阅 PEP457
, PEP570
, PEP3102
。
许多这些信息可以从函数的固有 code
对象中获得,它具有以下属性:
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')
但是,这些内容描述性不够,也不容易访问且仅供 python 内部使用。因此,除非您绝对需要自定义函数,否则 inspect.getfullargspec
可能是最佳选择。
fullargspec
的输出是 namedtuple
您可以轻松访问不同的字段:
>>> argspecs = inspect.getfullargspec(qux)
>>> argspecs.args
['a']
>>> argspecs.kwonlydefaults
{'b': 42}
如果你想要一个字典,你可以调用结果 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': {}}