只允许名称参数的函数

Bar*_*cki 5 python arguments function cookbook python-2.7

我在Python Cookbooks中阅读了一个解决方案,用于创建仅允许名称参数的函数.我编写了自己的代码来试试:

class Reporter(object):
    def __init__(self, *, testline=None, sw_ver= None, directory=None):
        pass

if __name__ == "__main__"
    r = Reporter()
Run Code Online (Sandbox Code Playgroud)

但是解释器显示此错误:

File "Reporter.py", line 6
    def __init__(self, *, testline=None, sw_ver= None, directory=None):
                        ^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)

为什么会显示这个?

Pad*_*ham 7

您使用的代码有效的语法,但对于python3,所以本书必须使用python3语法,它只允许关键字参数,pep-3102:

python 3新语法

您还可以在参数列表中使用bare*来表示您不接受可变长度参数列表,但是您确实只有关键字参数.

使用您的代码并在python 3中传递非关键字会出错,但原因不同:

TypeError                                 Traceback (most recent call last)
<ipython-input-2-b4df44fa1e0c> in <module>()
      1 if __name__ == "__main__":
----> 2         r = Reporter(4)
      3 

TypeError: __init__() takes 1 positional argument but 2 were given
Run Code Online (Sandbox Code Playgroud)

使用关键字后,它可以正常工作:

In [4]: if __name__ == "__main__":
             r = Reporter(testline=4)
   ...:     
Run Code Online (Sandbox Code Playgroud)

使用具有相同语法的函数可能会产生更明显的错误:

def f(*, foo=None, bar=None):
    return foo, bar


In [6]: f(4)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-a122d87dbe99> in <module>()
----> 1 f(4)

TypeError: f() takes 0 positional arguments but 1 was given
Run Code Online (Sandbox Code Playgroud)

如果你想允许一些位置args并且传递了可选的关键字args但是只有名字,那么它也很有用:

def f(a,b, *, foo=None, bar=None):
    return a, b, foo, bar
Run Code Online (Sandbox Code Playgroud)

然后通过3位置args将出错:

In [8]: f(1,2,3)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-b61741968103> in <module>()
----> 1 f(1,2,3)

TypeError: f() takes 2 positional arguments but 3 were given
Run Code Online (Sandbox Code Playgroud)


spe*_*ras 5

我最近收到了关于这个答案的评论.
→请注意它的目标是python2,因为OP用python2.7明确地标记了他的问题.对于python3,请参阅Padraic Cunningham的回答.

[原始答案]

你可能不会*单独使用它.在函数声明中,它表示"解压缩此变量中的任何其他未命名参数",因此您必须为其指定变量名称.

您可以通过给它命名来实现您想要的,然后检查它是否为空,如下所示:

class Reporter(object):
    def __init__(self, *args):
        assert not args, "Reporter.__ini__ only accepts named arguments"
Run Code Online (Sandbox Code Playgroud)

然后你想要添加你可以允许的参数,如下所示:

# won't work
def __init__(self, *args, testline=None, sw_ver= None, directory=None):
Run Code Online (Sandbox Code Playgroud)

......除了*args需要在最后.但是如果你把它们放在最后,你会发现你仍然可以先传递未命名的其他参数.

你必须扭转逻辑,只采取kwargs.

class Reporter(object):
    def __init__(self, **kwargs):
        testline = kwargs.pop('testline', None)
        sw_ver = kwargs.pop('sw_ver', None)
        directory = kwargs.pop('directory', None)
        assert not kwargs, 'Unknown arguments: %r' % kwargs
Run Code Online (Sandbox Code Playgroud)

现在,如果有人试图提供未命名的辩论,他们将被拒绝.


Reu*_*ani 2

星号运算符 ( *) 用于解包。您不能将其用作参数。

\n\n

您可能想阅读可变长度参数元组

\n\n
\n

函数可以采用可变数量的参数。以 * 开头的参数名称\n 将参数收集到一个元组中。例如,\n printall 接受任意数量的参数并打印它们:

\n
\n\n
def printall(*args):\n    print args\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

Gather 参数可以具有任何您喜欢的名称,但 args 是常规名称。这里\xe2\x80\x99是该函数的工作原理:

\n
\n\n
>>> printall(1, 2.0, \'3\') (1, 2.0, \'3\')\n
Run Code Online (Sandbox Code Playgroud)\n