Help us understand the problem. What is going on with this article?

PEP3102が私から数時間を奪い去った日

More than 3 years have passed since last update.

python3.6 わりと好きです。PEP498 すてきです。
しかし今回の主犯はPEP3102、keyword only argument です。

イテレーション開発のおともに、keyword only argument

ざっくり説明すると、

def ham(a1, a2, *, kw1, kw2='にゃーん', kw3):
    pass

こんな感じで、単独の*以降が keyword only になり、
kw1がpositionalに渡せなくなったり、kw3のようにデフォルト値ついてるkw2の後にデフォルト値を持たない引数を追加出来たりします(3.0から)。

という訳で、クラスメソッドに機能がふわふわと変化することの多い無計画な柔軟な開発では、引数を並べる順番を間違えて事故ることがないように、ほとんど全てを keyword only にしてしまいたくなります。

class A:
    def ham(
            self, *,
            all, the, arguments,
            may, as_well, be, kwargs
    ):
            print(f"{all} {the} {arguments} {may} {as_well} {be} {kwargs}")
>>> A().ham(**{name: name.upper() for name in A.ham.__code__.co_varnames if name != 'self'})
ALL THE ARGUMENTS MAY AS_WELL BE KWARGS

こんな感じです。

ある日突然いじめに

そんなこんなでPEP3102を愛して止まなかった私は、その日もいつも通り

class B:
    def egg(
            self, *
            first, argument,
            not_recognized="\^o^/"
    ):
        print(first, argument, not_recognized)

こんな感じのものを書いていました。すると、

>>> B().egg(first=1, argument=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: egg() got an unexpected keyword argument 'first'

!??
first が unexpected keyword だと言われてしまいました。

  1. first のスペル間違えたのだろうか?

    • 間違ってなかった。
  2. egg のスペル間違えたのだろうか?

    • 実際は B.egg はスーパークラスから呼ばれるオーバーライドメソッドであったため、egg(本当はもっと長ったらしい名前)のスペルを間違ったのではと推測するも、残念ながら(?)合ってた。
  3. なぜだ。内部情報を見てみる。

>>> B.egg.__code__.co_varnames
('self', 'argument', 'not_recognized', 'first')
>>> B.egg.__code__.co_kwonlyargcount
2

first は引数ですが、keyword only argument は2個(argumentnot_recognized)で、やはりなんかおかしいです。
(実際は上記2.を確かめるために呼び出し元の logger に投げてました)

なんかおかしいのはわかったのですが、結局わからないまま一日が終わり、眠れぬ枕を涙で濡らしました。

天祐

翌朝気づきました。

class B:
    def egg(
            self, *
            first, argument,
            not_recognized="\^o^/"
    ):
        print(first, argument, not_recognized)

L3: *の後に,がありません。

つまり、

class B:
    def egg(self, *first, argument, not_recognized="\^o^/"):
        print(first, argument, not_recognized)

こういうことになっていました \^o^/

flake8さん、教えてよ。。。
まあflake8さんにとって、これは

apple_pen = (
    apple
    + pen
)

のようなものの、単項演算子バージョンに過ぎないということなのだろう。

まとめ

linter だいじ。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away