はじめに
ナムコ! nikkieです。
標準ライブラリの中でとりわけヘビーユースしているargparse1。
Pythonスクリプトをコマンドラインツールにできます2。
argparseを使ったスクリプトをVS Codeで開発するうえで、型の表示を改善する小ネタです。
目次
- はじめに
- 目次
- parse_argsが返すNamespaceの属性の型がAny問題
- parse_argsには、namespace引数がある
- 2回型を書くのがちょっと面倒 ー Pydanticを使ってみようかな?
- 終わりに
parse_argsが返すNamespaceの属性の型がAny問題
% python -V Python 3.11.8
import argparse from pathlib import Path parser = argparse.ArgumentParser() parser.add_argument("path", type=Path) args = parser.parse_args() print(args.path)
parse_args()
はNamespaceのインスタンスを返します。
Namespaceとは「単に読みやすい文字列表現を持った object のサブクラス」3。
args.path
の部分にマウスカーソルを当てると、型はAny
です。
parse_argsには、namespace引数がある
「VS Codeで対処法はないかな〜」と、Pylanceまわりを調べていたら、こんなコメントが!
https://github.com/microsoft/pylance-release/issues/628#issuecomment-730628740
@dataclass class Args: x: int ... parser.add_argument('--x', type=int) parser.parse_args(['--x', '123'], Args())
「こんなことできるの!?」とドキュメントを見ると、
https://docs.python.org/ja/3/library/argparse.html#the-parse-args-method
namespace - 属性を代入するオブジェクト。デフォルトでは、新しい空の Namespace オブジェクトです。
空のNamespaceにparse_args()
が属性を代入して返していたんですね。
取り上げたコメントの例をVS Codeで書いたとしましょう。
parse_args()
は、Args
クラスのインスタンスに属性x
を指定して返します。
返り値の属性x
はArgs
クラスの属性ですから(Any
ではなく)int
という型が見えます。
上で使ったスクリプトを書き直しましょう。
マウスカーソルを当てると、型はPath
🙌
2回型を書くのがちょっと面倒 ー Pydanticを使ってみようかな?
上の例だとデータクラスArgs
と、add_argument()
で2回同じ型を書くのがちょっと面倒ですよね。
浮かんだアイデアが、Pydanticのデータクラスで型変換を使い、add_argument()
に型を書かずに済ませる方法。
Pydanticはパースして出力を保証してくれる4ので、argparseでは型の変換までしないという発想です。
これも動きました!5
pipx run ./script.py path/to/awesome
6
終わりに
parse_argsの返り値の属性は型がAny問題、私はすっかり慣れてしまっていたのですが、「つらくないですか?」という声をきっかけに対処法を見つけることができました。
namespace引数でクラスを渡せて、クラスのインスタンスとしてパースできるんですね!
これはますますヘビーユースしてしまいそうです。