delhi09の勉強日記

技術トピック専用のブログです。自分用のメモ書きの投稿が多いです。あくまで「勉強日記」なので記事の内容は鵜呑みにしないでください。

Pythonのimport文の並び順のフォーマットについて【isort】

前回の記事に続いて、Pythonのimport文の並び順のフォーマットについて書く。

isortについて

Pythonにはisortというimport文のフォーマッターが存在する。
機能概要としては、import文を以下のセクション順にソートしてくれる。


また、各セクション内のimport文の並び順はアルファベット順にソートしてくれる。

公式ドキュメントより引用

isort parses specified files for global level import lines (imports outside of try / except blocks, functions, etc..) and puts them all at the top of the file grouped together by the type of import:

  • Future
  • Python Standard Library
  • Third Party
  • Current Python Project
  • Explicitly Local (. before import, as in: from . import x)
  • Custom Separate Sections (Defined by forced_separate list in configuration file)
  • Custom Sections (Defined by sections list in configuration file)


Inside of each section the imports are sorted alphabetically. isort automatically removes duplicate python imports, and wraps long from imports to the specified line length (defaults to 79).

この記事ではisortの基本的な使い方について確認していく。

その前に

そもそも、Pythonの各種フォーマッター(black、yapf、autopep8)とは別にimport文のソート専用のライブラリが存在することに違和感を持った。
※ 例えばJavaではフォーマッターがimport文のソート機能も提供しているので、import文のソートだけ別のフォーマッターが必要ということはない。


そこで、Pythonの各種フォーマッター(black、yapf、autopep8)はimport文のソート機能を提供していないのか検証してみることにした。

PEP8に記載されているimport文のルール

各種フォーマッターの検証に移る前に、Pythonのフォーマットルールの原則はPEP8なので、まずは、import文のルールはPEP8に明文化されているのか?ということから確認する。

isortのソートルールと重なる部分に関して、PEP8における記載は以下

★記載されていること

  • import文は以下の順番でグループ化するべき
    • 1.標準ライブラリ
    • 2.サードパーティに関連するもの
    • 3.ローカルな アプリケーション/ライブラリ に特有のもの
  • 上のグループそれぞれの間には、1行空白を置くべき。

★記載されていないこと

  • import文の並び順はアルファベット順であるべき

PEP8(日本語訳)より引用

import文 は次の順番でグループ化すべきです:

  • 標準ライブラリ
  • サードパーティに関連するもの
  • ローカルな アプリケーション/ライブラリ に特有のもの

上のグループそれぞれの間には、1行空白を置くべきです。

従って、import文を

のセクション順に並べるということに関しては、PEP8に明文化されている。

各種フォーマッターにおける検証

isortの公式ドキュメントの以下のサンプルをそれぞれのフォーマッターでソートできるか実験していく。

from my_lib import Object

import os

from my_lib import Object3

from my_lib import Object2

import sys

from third_party import lib15, lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8, lib9, lib10, lib11, lib12, lib13, lib14

import sys

from __future__ import absolute_import

from third_party import lib3

print("Hey")
print("yo")


isortを使うと以下のようにソートされる。

from __future__ import absolute_import

import os
import sys

from third_party import (lib1, lib2, lib3, lib4, lib5, lib6, lib7, lib8,
                         lib9, lib10, lib11, lib12, lib13, lib14, lib15)

from my_lib import Object, Object2, Object3

print("Hey")
print("yo")

black

・実行コマンド

$ black sample.py

・結果
f:id:kamatimaru:20200428142300p:plain

一行が長いimport文の改行は行われたが、import文のソートは行われていない。

yapf

・実行コマンド

yapf -i -vv sample.py

・結果
f:id:kamatimaru:20200428142947p:plain

フォーマット箇所0

autopep8

・実行コマンド

autopep8 -i -a -a -v sample.py

・結果
f:id:kamatimaru:20200428142947p:plain

フォーマット箇所0

検証結果

black、yapf、autopep8はimport文のソート機能は提供していない。
従って、やはりimport文のsortにはisortが必要ということになる。(2020/4/28時点)

尚、blackには以下のissueが上っていたので、blackでもsort機能を提供してほしいという要望はあるようである。
github.com

isortのコマンドラインからの使い方

前置きが長くなったが、isortのコマンドラインからの使い方は以下

・インストール方法

$ pip install isort 

・実行方法(ファイル単位)

$ isort target_file.py

・実行方法(ディレクトリ配下全て)

$ isort -rc target_dir

・実行例(フォーマットが行われた場合)

$ isort sample.py
Fixing /path/to/dir/sample.py
$

・実行例(フォーマットが必要な箇所が存在しなかった場合)

$ isort sample.py
$

・フォーマット内容
例えば以下のようにフォーマットされる。(右がフォーマット後)
f:id:kamatimaru:20200428151911p:plain