Mar*_*ayo 94 python coding-style function parameter-passing
在Python中,您可能有一个函数定义:
def info(object, spacing=10, collapse=1)
Run Code Online (Sandbox Code Playgroud)
可以通过以下任何一种方式调用:
info(odbchelper)
info(odbchelper, 12)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)
Run Code Online (Sandbox Code Playgroud)
感谢Python允许任意顺序参数,只要它们被命名.
我们遇到的问题是我们的一些较大的功能增长,人们可能会之间添加参数spacing
和collapse
,这意味着错误的值可以将未命名的参数.此外,有时候我们并不总是清楚需要注意什么.我们正在采用一种方法强迫人们命名某些参数 - 不仅仅是编码标准,而且理想情况下是标志或pydev插件?
所以在上面的4个例子中,只有最后一个会通过检查,因为所有参数都被命名.
赔率是我们只会为某些功能打开它,但任何关于如何实现这一点的建议 - 或者如果它甚至可能会被赞赏.
Eli*_*sky 182
在Python 3中 - 是,您可以*
在参数列表中指定.
来自docs:
"*"或"*identifier"之后的参数是仅关键字参数,并且只能传递使用的关键字参数.
>>> def foo(pos, *, forcenamed):
... print(pos, forcenamed)
...
>>> foo(pos=10, forcenamed=20)
10 20
>>> foo(10, forcenamed=20)
10 20
>>> foo(10, 20)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes exactly 1 positional argument (2 given)
Run Code Online (Sandbox Code Playgroud)
这也可以与**kwargs
:
def foo(pos, *, forcenamed, **kwargs):
Run Code Online (Sandbox Code Playgroud)
mar*_*ega 26
您可以通过以下方式定义函数来强制人们在Python3中使用关键字参数.
def foo(*, arg0="default0", arg1="default1", arg2="default2"):
pass
Run Code Online (Sandbox Code Playgroud)
通过使第一个参数成为没有名称的位置参数,您可以强制调用该函数的每个人使用我认为您所询问的关键字参数.在Python2中,唯一的方法是定义一个这样的函数
def foo(**kwargs):
pass
Run Code Online (Sandbox Code Playgroud)
这会迫使调用者使用kwargs,但这不是一个很好的解决方案,因为你必须检查只接受你需要的参数.
Mar*_*ssi 10
确实,大多数编程语言都将参数顺序作为函数调用契约的一部分,但这不是必须的.为什么会这样?我对这个问题的理解是,如果Python在这方面与其他编程语言有任何不同.除了Python 2的其他好答案外,请考虑以下内容:
__named_only_start = object()
def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1):
if _p is not __named_only_start:
raise TypeError("info() takes at most 3 positional arguments")
return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse)
Run Code Online (Sandbox Code Playgroud)
调用者能够提供参数spacing
和collapse
位置(没有例外)的唯一方法是:
info(arg1, arg2, arg3, module.__named_only_start, 11, 2)
Run Code Online (Sandbox Code Playgroud)
在Python中,不使用属于其他模块的私有元素的惯例已经非常基本.与Python本身一样,这种参数约定只是半强制执行.
否则,呼叫需要采用以下形式:
info(arg1, arg2, arg3, spacing=11, collapse=2)
Run Code Online (Sandbox Code Playgroud)
一个电话
info(arg1, arg2, arg3, 11, 2)
Run Code Online (Sandbox Code Playgroud)
将值11分配给参数_p
,并由函数的第一条指令提升异常.
特点:
_p=__named_only_start
的参数在位置上(或通过名称)被接纳._p=__named_only_start
必须仅由名称提供(除非__named_only_start
获得并使用有关特殊哨兵对象的知识).优点:
__named_only_start
相应位置的sentinel对象切换到位置模式.缺点:
__named_only_start
正确位置的sentinel对象切换到位置模式.是的,这也可以看作是专业人士.请记住,这个答案仅对Python 2有效.Python 3实现了其他答案中描述的类似但非常优雅的语言支持机制.
我发现,当我敞开心扉思考它时,没有任何问题或其他决定似乎是愚蠢,愚蠢或者只是愚蠢.恰恰相反:我通常学到很多东西.
您可以通过在Python 2和Python 3中工作的方式实现这一点,方法 是使用"自然"不会出现的默认值"伪造"第一个关键字参数.该关键字参数前面可以有一个或多个没有值的参数:
_dummy = object()
def info(object, _kw=_dummy, spacing=10, collapse=1):
if _kw is not _dummy:
raise TypeError("info() takes 1 positional argument but at least 2 were given")
Run Code Online (Sandbox Code Playgroud)
这将允许:
info(odbchelper)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)
Run Code Online (Sandbox Code Playgroud)
但不是:
info(odbchelper, 12)
Run Code Online (Sandbox Code Playgroud)
如果将功能更改为:
def info(_kw=_dummy, spacing=10, collapse=1):
Run Code Online (Sandbox Code Playgroud)
然后所有参数必须有关键字,info(odbchelper)
不再有效.
这将允许您在之后的任何位置放置其他关键字参数_kw
,而不必强迫您在最后一个条目之后放置它们.这通常是有道理的,例如逻辑分组或按字母顺序排列关键字有助于维护和开发.
因此,无需def(**kwargs)
在智能编辑器中恢复使用和丢失签名信息.您的社交合同是通过强制(其中一些)要求关键字来提供某些信息,这些信息的提供顺序已变得无关紧要.
python3 仅关键字参数 ( *
) 可以在 python2.x 中模拟**kwargs
考虑以下 python3 代码:
def f(pos_arg, *, no_default, has_default='default'):
print(pos_arg, no_default, has_default)
Run Code Online (Sandbox Code Playgroud)
及其行为:
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 3 were given
>>> f(1, no_default='hi')
1 hi default
>>> f(1, no_default='hi', has_default='hello')
1 hi hello
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() missing 1 required keyword-only argument: 'no_default'
>>> f(1, no_default=1, wat='wat')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got an unexpected keyword argument 'wat'
Run Code Online (Sandbox Code Playgroud)
这可以使用以下内容进行模拟,请注意,我已经自由地切换TypeError
到KeyError
“必需的命名参数”情况,将其设置为相同的异常类型也不会做太多工作
def f(pos_arg, **kwargs):
no_default = kwargs.pop('no_default')
has_default = kwargs.pop('has_default', 'default')
if kwargs:
raise TypeError('unexpected keyword argument(s) {}'.format(', '.join(sorted(kwargs))))
print(pos_arg, no_default, has_default)
Run Code Online (Sandbox Code Playgroud)
和行为:
>>> f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() takes exactly 1 argument (3 given)
>>> f(1, no_default='hi')
(1, 'hi', 'default')
>>> f(1, no_default='hi', has_default='hello')
(1, 'hi', 'hello')
>>> f(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in f
KeyError: 'no_default'
>>> f(1, no_default=1, wat='wat')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in f
TypeError: unexpected keyword argument(s) wat
Run Code Online (Sandbox Code Playgroud)
该配方在 python3.x 中同样有效,但如果您仅使用 python3.x,则应该避免