1. ホーム
  2. python

args構文を使用する引数リストで、最後のカンマがSyntaxErrorになるのはなぜですか?

2023-12-09 08:39:37

質問

で末尾にコンマを使用できないのはなぜですか? *args を使うことができないのでしょうか? 言い換えれば、これは動作します

>>> f(1, 2, b=4,)

しかし、これでは

>>> f(*(1, 2), b=4,)
  File "<stdin>", line 1
    f(*(1, 2), b=4,)
                   ^
SyntaxError: invalid syntax

これはPython2でもPython3でも同じです。

どのように解決するのですか?

を見てみましょう。 言語仕様 :

call                 ::=  primary "(" [argument_list [","]
                          | expression genexpr_for] ")"
argument_list        ::=  positional_arguments ["," keyword_arguments]
                            ["," "*" expression] ["," keyword_arguments]
                            ["," "**" expression]
                          | keyword_arguments ["," "*" expression]
                            ["," "**" expression]
                          | "*" expression ["," "*" expression] ["," "**" expression]
                          | "**" expression
positional_arguments ::=  expression ("," expression)*
keyword_arguments    ::=  keyword_item ("," keyword_item)*
keyword_item         ::=  identifier "=" expression

気になる部分までふるい落とそう。

call                 ::=  primary "(" [argument_list [","]] ")"
argument_list        ::=  positional_arguments ["," keyword_arguments]
                            ["," "*" expression] ["," keyword_arguments]
                            ["," "**" expression]
positional_arguments ::=  expression ("," expression)*
keyword_arguments    ::=  keyword_item ("," keyword_item)*
keyword_item         ::=  identifier "=" expression

ということは、関数呼び出しの引数の後に、追加で , . これはcpythonの実装のバグのように見えます。

のようなものです。 f(1, *(2,3,4), ) のようなものは、この文法に従えば動作するはずですが、CPythonではそうではありません。


以前の回答で エリック がリンクしていた CPython文法仕様 にリンクされており、上記の文法のCPythonの実装が含まれています。以下、それを紹介します。

arglist: (argument ',')* ( argument [',']
                         | '*' test (',' argument)* [',' '**' test] 
                         | '**' test
                         )

なお、この文法は ではありません。 であることに注意してください。私はこれを実装上のバグと考えます。


CPythonの実装には、さらに問題があることに注意してください。これもサポートされるべきです。 f(*(1,2,3), *(4,5,6))

しかし奇妙なことに、この仕様では f(*(1,2,3), *(4,5,6), *(7,8,9))

もっと見ていくと 仕様のこの部分を修正する必要があると思います。これは許される。 f(x=1, *(2,3)) , しかし、これは許されない。 f(x=1, 2, 3) .


また、元の質問の参考になるかもしれませんが、CPythonでは *args または **kwargs という機能があります。これがダサいというのは同感です。