はじめに
諸事情からpythonの Full Grammar specificationを読んでいたら、普段雰囲気でなんとなく使っていたpythonのあまり目にしない機能をいくつか見つけたので紹介してみます。
明日から使える・・・かどうかはわかりませんが、明日同僚にどや顔するくらいの使い道があること間違いなし!
紹介順には特に意図はありません。
1. PEP570 Python Positional Only Parameters [Python 3.8~]
>>> def id(x): return x
...
>>> id(2) # (i)
2
>>> id(foo=2) # (ii)
2
実は、上のように定義されたpythonの関数id
は引数を(i)のようにして渡すこともできるほか、(ii)のようにラベル付きで渡してあげることもできます。このような渡し方ができるパラメータはそれぞれpositional parameter, keyword parameterと呼ばれます。関数の定義時にデフォルト値を与えずに定義したパラメータについてもkeyword parameterとして扱うことができる、という時点で私の知らない話だったのですが、実はさらに、positionalとしてしか使えないパラメータ、keywordとしてしか使えないパラメータを指定することができるようです。これらは、positional/keyword-only parameterと呼ばれます。例を見てみましょう。
>>> def id3(x, /, y, *, z): return x, y, z
...
>>> id3(1, 2, z=3)
(1,2,3)
>>> id3(1, y=2, z=3)
(1,2,3)
>>> id3(x=1, 2, z=3)
SyntaxError: positional argument follows keyword argument
>>> id3(1, 2, 3)
TypeError: id3() takes 2 positional arguments but 3 were given
/
の左側にあるパラメータはpositional-only parametersとなり、keyword parameterとして使うことはできません。他方、*
の右側にあるパラメータはkeyword-only parametersとなり、positional paramterとして使うことはできません。したがって、上の例のように、yは単に2を与えても、y=2
のような形で与えても機能しますが、x
とz
についてはそれぞれpostional、keyword parameterとして与えないとエラーになる、という訳です。
2. PEP3132 Extended Iterable Unpacking [Python 3.0~]
関数型言語なんかだと、パターンマッチの中でリストの先頭とそれ以外を別の変数に束縛したりとかしますよね。実はpythonでも似たような事ができます。それが、Extended Iterable Unpackingです。
>>> a, *b = [1,2,3]
>>> a
1
>>> b
[2,3]
例を見てもらえればわかる通り、変数へのiterableの代入時にスター(*
)を付けた変数に対して、「残りの部分」を代入できるような構文です。
PEP3132の例をみると、もう少し柔軟なこともできるようです:
>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]
3. PEP572 Assignment Expressions [Python 3.8~]
議論を呼んだ(そして最終的にはPython作者のGuidoを優しい終身の独裁者から引退させた)らしい問題の拡張。
pythonでは代入は「文」であるためC言語などで見るような、次のようなコードは書けません(でした)
while(x = 1) {
//do something
}
しかし、「式」としての代入もあったほうが便利だろうというのがこちらの提案。次のようなコードが書けるようになりました。
while(foo:=False):
print("You'll never see me.")
・・・Guido氏のBDFL引退騒動にまで発展した割に、僕の周りだとあんまりこの演算子が使われているところを見ないような・・・
4. 関数引数末尾のカンマ
pythonでは次のように、リストやタプルの末尾に余計なカンマが付いていて良い、というルールになっているのは皆さんご存じかと思います。
>>> a = [1,2,]
>>> a
[1, 2]
>>> b = ("a", 2,)
>>> b
('a', 2)
実は、関数定義や呼び出しでの引数にも末尾に余計なカンマが付くことを許しています。
>>> def hoge(x,):
... return x
...
>>> hoge(2)
2
>>> len([1,2,],)
2
5.
以下追記予定